Analysis and Results
Software/Libraries
This work was produced with the R language and the following packages:
# packages used
library(bold)
library(tidyverse)
library(ggthemes)
library(vegan)
library(patchwork)
library(leaflet)
library(gt)
library(kableExtra)
library(ggrepel)
library(scales)
library(rcartocolor)
library(igraph)
library(plotly)
Downloading BOLD specimen records
All specimen records for Araneae were downloaded from the BOLD api on 2020-09-29. I also obtained the World spider catalog dataset (on the same date) as a reference for comparison of taxonomic identifiers.
## build the url for downloading
# taxon <- "Araneae"
# taxon <- paste0("taxon=", taxon)
# prefix <- "http://www.boldsystems.org/index.php/API_Public/specimen?"
# fmt <- "&format=tsv"
# url <- paste0(prefix, taxon, fmt)
#
# # download, parse data
# Araneae.df <- read_delim(url, delim = '\t',guess_max = 10000)
# write_rds(Araneae.df, "./data/BOLD.araneae.rds")
#
BOLD ‘Aranaea’ dataset
The dataset used in this analysis contained all the available specimen records of the order Araceae. Any records lacking BIN identifiers or geographic metadata were removed. There are 95,479 specimen records in this selection, representing 9,757 BIN clusters and these were collected in 136 countries. Specimen records were grouped by absolute latitude and classified as tropical (0-20˚), sub-tropical (20-40˚), temperate (40-60˚), or extreme (60-90˚). Similarly, countries were grouped by their mean latitude of all specimens for diversity analyses.
Table 1. Summary of Araneae specimen records from the BOLD database that were used in this analysis.
kable(data_summary, format = 'pipe',escape = TRUE)
| Specimen records in BOLD |
124,682 |
| Records selection (not missing BIN and country data) |
95,910 |
| Number of unique BINs in selected records |
9,845 |
| Unique family taxa |
113 |
| Unique genus taxa |
1,122 |
| Unique species taxa |
3,822 |
| Source countries in selected records |
136 |
| Latitude range |
-55.6 : 82.5 |
Specimen Map
A map showing the geographic distribution of spider specimens in the BOLD database. Strong North American and European sampling bias is evident; the Southern hemisphere is not well represented, especially Africa and Central Asia.
## group specimens on a 1deg grid
spider.map.df <- Araneae.df %>%
# round coords to nearest deg.
mutate(lat = round(lat),
lon = round(lon)) %>%
# group/count all specimens with same coords
group_by(lat, lon) %>%
mutate(n=n(),
BINs = length(unique(bin_uri))) %>%
select(lat, lon, n, BINs) %>%
distinct() %>%
# create popup labels with info
mutate(popups = paste0(
"<b>Lat: </b>", lat,
'<br><b>Long: </b>', lon,
"<br><b>Specimens: </b>", n,
"<br><b>BINs: </b>", BINs),
labs = paste(n, 'specimens')
) %>%
filter(!(is.na(lat)|is.na(lon)))
# create map
make.spider.map <- function(spider.map.df){
spider.map <- leaflet(spider.map.df) %>%
setView(zoom=1, lat=30, lng=5) %>%
addProviderTiles(providers$CartoDB.Positron)
# add latitude lines that samples were grouped by
for (i in c(-60, -40, -20, 0, 20, 40, 60)) {
spider.map <- spider.map %>%
addPolylines(lng = c(-360:360, 360:-360),
lat = rep(i, times=720), weight = 0.4)
}
spider.map <- spider.map %>%
addCircleMarkers(
color = '#f20000',
lng = ~lon,
lat = ~lat,
radius = ~(log(n)+1)*0.4,
fillOpacity = 0.3,
stroke = FALSE,
popup = ~popups,
label = ~labs
)
return(spider.map)
}
make.spider.map(spider.map.df)
Figure 1. Geography of BOLD spider specimens. Markers show the location and amount of specimens collected at each location; specimens were binned into a 1deg x 1deg grid for counting. Latitude lines correspond to the zones that were considered in the geographic analysis of spider diversity. (An interactive version with zoom & labels is presented in the accompanying html-notebook ‘JMogg_spider_diversity_notebook.html’)
Composition and sampling depth by latitude
# tablulate specimen records count by BIN
bin.table <- Araneae.df %>%
count(bin_uri)
# plot histogram of specimen counts for BINs (bin size distribution)
bin.hist <- bin.table %>%
ggplot(aes(x = n)) +
geom_histogram(bins = 100) +
scale_x_log10() + scale_y_log10() +
scale_fill_viridis_d() +
labs(x = 'Specimens assigned to BIN',
y = 'Frequency') +
theme_classic()
# Araneae.df2 <- Araneae.df %>%
# mutate(plotly.labs = paste("<b>Lat:</b>", lat,
# '<br><b>Family</b>:, family_name))
# Specimen distribution by latitude
spec.lats.bar <- ggplot(Araneae.df, aes(y=lat, fill = family_name)) +
geom_histogram(alpha = 0.8, colour = 'lightgrey', orientation = 'y',
show.legend = FALSE) +
scale_fill_viridis_d(option = 'C') +
labs(y = 'Latitude', x = 'Specimen count') +
theme_classic() +
theme(legend.position = 'null')
# show both plots
ggplotly(spec.lats.bar)
Figure 2a. A plot showing the number of samples collected by latitude; colors correspond to different spider families; popup labels show family name and specimen count - please ignore latitude in popup labels and read from y-axis. Families can be hidden/revealed by clicking icons on the legend (scroll to browse).
bin.hist

Figure 2b. A histogram showing the distribution of the number of specimens that have been assigned to each BIN.
Rarefaction & Species Abundance Curves
Rarefaction were computed using the vegan::rarecurve function for specimens grouped by each of country and latitude zone.
# # full data rarefaction
# Araneae.rar <- rarecurve(Araneae.df.bins,)
# Araneae.rar <- tibble(y = Araneae.rar[[1]]) %>%
# mutate(x=row_number())
# write_rds(Araneae.rar, "./data/Araneae.rarefaction.rds")
#
# ## rarefaction curves by lat zone
# Araneae.zone.rar <- rarecurve(Araneae.zone.bins)
#
# # manipulate list output from vegan back into tidy data
# Araneae.zone.rar <- tibble(zone = rownames(Araneae.zone.bins),
# list = Araneae.zone.rar) %>%
# # spread list into individual columns
# unnest_wider(col = list) %>%
# # get long form table
# pivot_longer(cols = -zone) %>%
# # remove rows missing value & useless names column
# filter(!is.na(value)) %>%
# select(-name) %>%
# # create vector for sampling depth
# group_by(zone) %>%
# mutate(sample_size = row_number())
# write_rds(Araneae.zone.rar, "./data/Araneae.zones.rarefaction.rds")
#
# ## rarefaction curves by country
# Araneae.country.rar <- rarecurve(Araneae.country.bins)
#
# # manipulate list output from vegan back into tidy data
# Araneae.country.rar <- tibble(Country = rownames(Araneae.country.bins),
# list = Araneae.country.rar) %>%
# unnest_wider(col = list) %>%
# pivot_longer(cols = -Country) %>%
# filter(!is.na(value)) %>%
# select(-name) %>%
# group_by(Country) %>%
# mutate(sample_size = row_number())
# write_rds(Araneae.country.rar, "./data/Araneae.country.rarefaction.rds")
Species accumulation curves were computed using the vegan::specaccum function for specimens grouped by each of country and latitude zone.
# ## Species accumulation curves
# # specaccum by country
# Specaccum.country <- specaccum(Araneae.country.bins)
# Specaccum.country <- tibble(
# sites = Specaccum.country['sites'],
# richness = Specaccum.country['richness'],
# sd = Specaccum.country['sd'],
# ) %>%
# unnest(cols = c(sites, richness, sd)) %>%
# mutate(sd1 = ifelse(richness-sd>=0, richness-sd, 0),
# sd2 = richness+sd)
# write_rds(Specaccum.country, "Specaccum.country.rds")
#
# # specaccum by zone
# Specaccum.zone <- specaccum(Araneae.zone.bins)
# Specaccum.zone <- tibble(
# sites = Specaccum.zone['sites'],
# richness = Specaccum.zone['richness'],
# sd = Specaccum.zone['sd'],
# ) %>%
# unnest(cols = c(sites, richness, sd)) %>%
# mutate(sd1 = ifelse(richness-sd>=0, richness-sd, 0),
# sd2 = richness+sd)
# write_rds(Specaccum.zone, "./data/Specaccum.zone.rds")
Plots were created for the rarefaction and species accumulation curves in the following code:
## RAREFACTION
# read in rar. curve data computed above
Araneae.rar <- read_rds("./data/Araneae.rarefaction.rds")
Araneae.zone.rar <- read_rds("./data/Araneae.zones.rarefaction.rds")
Araneae.country.rar <- read_rds("./data/Araneae.country.rarefaction.rds")
# rarefaction plot for entire dataset
plot.rar.full <- Araneae.rar %>%
ggplot(aes(x=x/1000, y=y)) +
geom_line() +
labs(y = 'Unique BINs', x = 'Sample size (k)') +
theme_classic()
# rarefaction curves for latitude zones
plot.rar.zone <- ggplot(Araneae.zone.rar,
aes(x=sample_size/1000, y = value,
group = zone, colour = zone)) +
geom_line(alpha = 0.7) +
scale_colour_discrete('Lat. zone') +
labs(x = 'Sample size (k)', y = 'Unique BINs') +
theme_classic()
# added lat zone labels to country rarefaction curves data for plot
Araneae.country.rar <- left_join(Araneae.country.rar, country_zones, by = 'Country')
# plot rarefaction curves for each country, colour by zone
plot.rar.country <-
Araneae.country.rar %>%
filter(!is.na(zone)) %>%
ggplot(aes(x=sample_size/1000, y = value)) +
geom_line(aes(group = Country, colour = zone), alpha = 0.7) +
# add labels for 10 most-sampled countries
geom_text_repel(data = country.specimens.table[1:10,],
aes(label = country, x = specimens/1000, y = species),
nudge_x = 0, size = 3,
na.rm = TRUE) +
scale_colour_discrete('Lat. zone') +
labs(x = 'Sample size (k)', y = 'Unique BINs') +
theme_classic()
plot.rar.country2 <-
Araneae.country.rar %>%
filter(!is.na(zone)) %>%
ggplot(aes(x=sample_size, y = value)) +
geom_line(aes(group = Country, colour = zone), alpha = 0.7) +
# add labels for 10 most-sampled countries
geom_text_repel(data = country.specimens.table[1:10,],
aes(label = country, x = specimens, y = species),
nudge_x = 0, size = 3,
na.rm = TRUE) +
scale_colour_discrete('Lat. zone') +
labs(x = 'Sample size', y = 'Unique BINs') +
theme_classic() +
xlim(c(0, 500)) +
ylim(c(0, 340))
## SPECIES ACCUMULATION
Specaccum.country <- read_rds("./data/Specaccum.country.rds")
Specaccum.zone <- read_rds("./data/Specaccum.zone.rds")
# plot species accumulation by country
plot.Specaccum.country <- ggplot(Specaccum.country) +
geom_ribbon(aes(x=sites, y=richness, ymin = sd1, ymax = sd2),
fill = 'cornflowerblue', alpha = 0.3) +
geom_line(aes(x = sites, y = richness),
size = 1.3, colour = 'blue4', alpha = 0.7) +
labs(y = 'BIN Richness', x = 'Countries') +
theme_classic()
# plot species accumulation by latitude zone
plot.Specaccum.zone <- ggplot(Specaccum.zone) +
geom_ribbon(aes(x=sites, y=richness, ymin = sd1, ymax = sd2),
fill = 'red', alpha = 0.2) +
geom_line(aes(x = sites, y = richness),
size = 1.3, colour = 'red3', alpha = 0.7) +
labs(y = 'BIN Richness', x = 'Latitude zones') +
theme_classic()
## create rarefaction/specaccum plots figure
# show rarefaction plots panel with patchwork::
(plot.rar.full + plot.rar.zone) /
(plot.rar.country + plot.rar.country2) /
(plot.Specaccum.country + plot.Specaccum.zone) +
plot_annotation(tag_levels = 'A') +
plot_layout(guides = 'collect') &
theme(plot.tag.position = c(0, 1),
legend.position = "right",
plot.tag = element_text(size = 8, hjust = 0, vjust = 0))

Figure 3. A-D: Rarefaction curves for entire collection of BOLD spider specimens (A), by latitude zone (B), and by source country (C). Because of the discrepency in sampling, a close-up of the countries’ rarefaction curves are shown for smaller sample sizes (D). Curves are coloured by latitude zone where applicable. Countries are assigned to latitude zones by the mean latitude of all their samples. Rarefaction curves were computed using the vegan::rarecurve function. EF: Species accumulation curves were computed using the vegan::specaccum function for specimens grouped by each of country (E) and latitude zone (F); lines show richness +/- sd.
Ordination by NMDS and species network anaylsis
# NMDS
zone.nmds <- metaMDS(Araneae.zone.bins, distance = 'bray', trace = FALSE)
# zone.nmds
par(mar=c(5,4,1,1))
plot(zone.nmds, alpha=0.5, cex = 0.7)
text(zone.nmds, display = 'sites', cex = 0.9)

Figure 5. NMDS of spider BIN abundances in four latitude zones using Bray distance and Wisconsin standardization of square-root-transformed abundances.
## Network plot with shared BINs between zones
Araneae.zone.bins <- read_rds("./data/Araneae.zone.bins.rds")
# make an edgelist for simple graph (for bins shared between zones)
edgelist <- tibble(
u = c(rownames(Araneae.zone.bins)),
v = rep(list(rownames(Araneae.zone.bins)),4)
) %>%
unnest(v) %>%
filter(!u==v)
# get rid of duplicate edges in edgelist (since graph is not directional)
edge.strings <- str_split(paste(edgelist$u, edgelist$v), ' ')
# sort edges to remove directionality
edgelist <- unique(lapply(edge.strings, function(x) unique(sort(x))))
# remove self-self edges
edgelist <- edgelist[which(lengths(edgelist)>1)]
# paste u v vertices for each edge to filter bins.edgelist later (below)
edgelist <- lapply(edgelist, function(x) paste0(x, collapse = ' '))
rm(edge.strings)
# Get list of unique bins for each zone from zone abund. matrix
zone.bins.list <- tibble(Araneae.zone.bins) %>%
mutate(zone = rownames(Araneae.zone.bins)) %>%
pivot_longer(-zone) %>%
filter(!value == 0) %>%
group_by(zone) %>%
mutate(bins = list(name)) %>%
select(-c(value, name)) %>%
distinct() %>%
mutate(uniques = unique(bins))
# Create matrix with sizes of intersect of unique bins between zones. Each col has the size of the intersection between a zone and each zone (self-self is on diagonal) - for network edge weights
bins.ls <- zone.bins.list %>%
select(zone, bins) %>%
mutate(Extreme = length(intersect(zone.bins.list[1, 3][[1]][[1]], bins[[1]])),
Temperate = length(intersect(zone.bins.list[2, 3][[1]][[1]], bins[[1]])),
`Sub-tropical` = length(intersect(zone.bins.list[3, 3][[1]][[1]], bins[[1]])),
Tropical = length(intersect(zone.bins.list[4, 3][[1]][[1]], bins[[1]])),
) %>%
select(-bins) %>%
pivot_longer(Extreme:Tropical) %>%
rename(zone1 = zone,
zone2 = name,
weight = value)
# Filter weighted edgelist to keep single edge for each pair (not bidirectional - made 'edgelist' at top of chunk)
bins.edges <- bins.ls %>%
filter(!zone1 == zone2) %>%
mutate(edge = paste(zone1, zone2)) %>%
filter(edge %in% edgelist) %>%
select(-edge)
# total number of unique bins at each zone - for vertex size
total_bins <- bins.ls %>%
filter(zone1 == zone2) %>%
select(-zone2) %>%
rename(size = weight)
net <- graph_from_data_frame(d= bins.edges, vertices = total_bins, directed = F)
#vertice properties
V(net)$color <- c( 'cyan', "gold", "tomato", "plum")
V(net)$size <- total_bins$size/100 + 20
# edge properties
E(net)$weight <- bins.edges$weight*100
E(net)$width <- sqrt(E(net)$weight)/20
E(net)$edge.label <- bins.edges$weight
E(net)$edge.color <- "gray90"
E(net)$arrow.size <- .0
# Plot species network
set.seed(4)
par(mar=c(1,1,1,1))
plot(net,
layout = layout.fruchterman.reingold(net),
label.dist = 2,
edge.label = bins.edges$weight,
edge.label.color ="navy",
edge.label.cex = 0.8,
edge.label.family = 'sans',
vertex.label = paste0(V(net)$name, '\n(', total_bins$size, ')'),
vertex.label.color="black",
vertex.label.family = 'sans',
vertex.label.font = 2,
vertex.label.cex=.7,
vertex.frame.color = 'white')

Figure 6. Network of latitude-zoned spider assemblages linked by shared barcodes shows that similarity increases with latitude. Vertices represent latitude zone and BIN richness; edges are wieghted by the number of shared BINs between zones.
Discussion
In this work I examined the latitudinal diversity gradient in DNA-barcoded spider specimens recorded in BOLD; as well as to evaluate geographical sampling bias in this collection. To this end, a number of ecological analysis were performed including rarefaction, species accumulation, and ordination. The Barcode of Life database (BOLD) contains a huge number of spider specimen records (124k) and associated DNA-barcode sequences (106k; table 1) (Ratnasingham and Hebert 2007, 2013). There is a surprisingly large number of unique DNA barcode indentifiers (BINs) compared to species names (9,845 vs 3,822). Additionally large number of specimens are missing taxonomic labels at the family, genus, and species levels (17k, 21k, and 23k records, respectively), indicating that barcode-based analysis is especially useful for spiders. Most barcodes have only a few specimens, and the number of specimens per barcode sequence has a negative binomial distribution (fig. 2 right)
To evaluate the global distribution of the sampling effort represented in the BOLD spider collection, all records having barcodes and geodata (96k) were binned into a 1 deg grid and mapped (fig. 1). Strong North American and European sampling bias is evident; vast swaths of Africa and Central Asia have no representatives. The sampling of spider specimens is heavily skewed to northern latitudes (fig. 2 left) though this is roughly proportional to overall landmass. While there are a large number of spider families represented in the dataset, a few families (Linyphiidae, Lycosidae and Araneidae) tend to dominate communities across latitudes.
Spiders biodiversity is generally known to decrease with distance from the equator (Platnick 1991; Piel 2018). To evaluate the latitudinal diversity gradient of the BOLD spiders data, I first grouped records into four ‘latitudinal communities’ based on absolute latitude: tropical (+/-0-20 deg), sub-tropical (20-40), temperate (40-60) and extreme (60+). Similarly, specimen-source countries were categorized into these zones based on the mean latitude of specimens collected in each country.
Diversity analyses of these national and latitudinal communities showed that diversity generally decreases with distance from the equator, as was expected from previous research (Platnick 1991; Piel 2018). Overall, the sub-tropical zone contained the greatest barcode (BIN) richness followed by the temperate and tropical zones (table 2, fig 2b.). Rarefaction analysis showed that the sub-tropical and tropical communities are fairly similar in terms of diversity and are more diverse than the temperate and extreme latitude zones (fig. 3b). When national communities are considered, we can see that there is a large degree of variance in diversity between countries at similar distances from the equator, and this is especially true for the communities of the few tropical nations examined (only fig. 3c,d).
When considering equal sample sizes, the sub-tropical zone had the greatest rarefied BIN richness but this was only slightly larger than the tropical zone (table 2, fig. 4). Temperate and extreme latitudes had relatively low Shannon diversity, while the subtropical-zone had a slightly greater Shannon diversity than the tropical zone. Simpson diversity was not very informative for differentiating communities at the zone or country level, with most values approaching 1. Anova tests of countries’ richness and Shannon index data showed that the differences in means between latitude zones were not statistically significant. This analysis was hindered by the low number of site countries having enough specimens (n>499, countries=21) and these were concentrated in the temperate and subtropical zones, leading to large error values in estimating the diversity of tropical and extreme zones. Overall, the BOLD spiders data follow the expected negative latitude-diversity trend; however, peak richness and diversity was observed in the sub-tropical zones (+/- 20-40 deg latitude).
Ordination and network analysis of latitude zone communities showed that the temperate and extreme zones were the most similar in composition and had the greatest number of shared BINs at 654 (figs. 5,6), representing 78% of the BINs from the extreme latitude community and 22% of the temperate community. This was contrasted by the relatively few bins shared between the tropical, sub-tropical, and temperate zones. From ordination, we see that the extreme and temperature communities are most similar in terms of composition while the sub-tropical and tropical zones are as dissimilar to the temperate and extreme zones as they are to each other.
The mapping of specimens and rarefaction curves produced from BIN abundances by country and latitude zone (fig. 2) both show a strong geographic bias in the database and an under-powered sampling of many regions, particularly at tropical latitudes. Despite the wide range of source countries, Canadian specimens account for nearly half the collection with the remaining records being predominantly from the US and handful of other countries. This ‘Boreal bias’ is a prevalent theme in ecology (Platnick 1991) and the BOLD data reflects this. As such, some results of this diversity analysis are particularly suspect. Brazil, for example, appears to have extremely low spider diversity but this is contrary to what is expected from the latitude-diversity trend and the highly-productive landscape.
In summary, BOLD data show decreasing trend in spider biodiversity with distance from the equator as has been previously described (Piel 2018, @Platnick1991). There is great variation in diversity between countries in the BOLD data and a limited number of tropical countries with adequate sampling. This made it difficult find significant changes in richness or diversity across latitudes. Sampling bias has affected the analysis to an extent but this is somewhat compensated for by the large volume of specimens collected and the use of broad latitude zones. The BOLD database is indeed a valuable resource for evaluating global ecological trends. BOLD’s value will continue to increase with the addition of collections from under-represented areas.
LS0tCnRpdGxlOiBEaXZlcnNpdHkgYW5hbHlzaXMgb2YgKkFyYW5lYWUqIChzcGlkZXJzKSBzcGVjaW1lbnMgaW4gdGhlIEJhcmNvZGUgb2YgTGlmZQogIERhdGFiYXNlCmF1dGhvcjogIkphc29uIEEuIE1vZ2dyaWRnZSIKZGF0ZTogIjIwMjAvMTAvMDciCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKICAgIHRvY19mbG9hdDogeWVzCiAgICBkZl9wcmludDogcGFnZWQKICAgIHRoZW1lOiBmbGF0bHkKICAgIGhpZ2hsaWdodDogdGV4dG1hdGUKYmlibGlvZ3JhcGh5OiByZWZlcmVuY2VzLmJpYgotLS0KCipTdWdnZXN0aW9uOiB1c2Ugb3B0aW9uICdoaWRlIGFsbCBjb2RlJyBpbiB0aGUgbWVudSBhdCB0b3AtcmlnaHQsIHRoZW4gZXhwYW5kIGNvZGUgY2h1bmtzIHdoZW4gaW50ZXJlc3RlZC4qPGJyPgoqTm90ZTogVGltZSBjb25zdW1pbmcgY29tcHV0YXRpb25zIGhhdmUgYmVlbiAjLWNvbW1lbnRlZCBvdXQgZm9yIGNvbnZlbmllbmNlLCBhZnRlciBkYXRhIHdlcmUgc2F2ZWQqCgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKCWVjaG8gPSBUUlVFLAoJbWVzc2FnZSA9IEZBTFNFLAoJd2FybmluZyA9IEZBTFNFCikKYGBgCgotLS0tLQoKIyBJbnRyb2R1Y3Rpb24KClNwaWRlcnMgYXJlIGFuIGluY3JlZGlibHkgZGl2ZXJzZSBvcmRlciBvZiBhcnRocm9wb2RzIHRoYXQgcGxheSB2aXRhbCByb2xlcyBpbiBkaXZlcnNlIGVjb3N5c3RlbXMsIHBhcnRpY3VsYXJseSBhcyBrZXkgcHJlZGF0b3JzIHRoYXQgbW9kdWxhdGUgYmlvbWFzcyBvbiBhIGdsb2JhbCBzY2FsZSBbQE55ZmZlbGVyMjAxN10uIFRoZXJlIGFyZSBjdXJyZW50bHkgNDgsNzg5IHNwZWNpZXMgZGVzY3JpYmVkIGluIHRoZSBXb3JsZCBzcGlkZXIgY2F0YWxvZyAoaHR0cHM6Ly93c2Mubm1iZS5jaC8pIGFuZCBub3ZlbCBzcGVjaWVzIGFyZSBiZWluZyBhZGRlZCBvbiBhIHJlZ3VsYXIgYmFzaXMuIERpZmZlcmVudGlhdGlvbiBvZiBzdWNoIGEgbGFyZ2UgbnVtYmVyIG9mIHNwZWNpZXMgYmFzZWQgb24gbW9ycGhvbG9neSBhbG9uZSBpcyB0cmVtZW5kb3VzbHkgY2hhbGxlbmdpbmcuIFRoaXMgZGlmZmljdWx0eSBpcyBjb21wb3VuZGVkIGJ5IG90aGVyIGluY29udmVuaWVudCBjaGFyYWN0ZXJpc3RpY3Mgb2Ygc3BpZGVycyBpbmNsdWRpbmcgc2V4dWFsIGRpbW9ycGhpc20sIGRldmVsb3BtZW50YWwgY2hhbmdlcyBpbiBtb3JwaG9sb2d5LCBhbmQgdGhlaXIgY3J5cHRpYyBsaWZlc3R5bGVzIFtAVHlhZ2kyMDE5XS4KCkFzIG1vcnBob2xvZ2ljYWwgY2xhc3NpZmljYXRpb24gb2YgbGFyZ2UgbnVtYmVycyBvZiBzcGlkZXJzIGlzIGdlbmVyYWxseSB0ZWRpb3VzIGFuZCBpbXByYWN0aWNhbCwgRE5BIGJhcmNvZGluZyBoYXMgYmVjb21lIHJvdXRpbmUgbWV0aG9kIGZvciBzcGVjaWVzIGlkZW50aWZpY2F0aW9uIGluIGVjb2xvZ2ljYWwgc3R1ZGllcyBbQFRhaGlyMjAxOV0uIFRoZSBjaGFyYWN0ZXJpc3RpY3Mgb2YgdGhlIG1pdG9jaG9uZHJpYWwgKmN5dG9jaHJvbWUgYyBveGlkYXNlKiBzdWJ1bml0IDEgKENPMSkgZ2VuZSBtYWtlIGl0IGFuIGlkZWFsIG1hcmtlciBmb3IgZGlmZmVyZW50aWF0aW5nIHNwZWNpZXMgW0BSYXRuYXNpbmdoYW0yMDA3OyBAUmF0bmFzaW5naGFtMjAxM10uIEluIGEgcmVsYXRpdmVseSBsaW1pdGVkIHRpbWUsIGEgbGFyZ2UgYW1vdW50IG9mIGJhcmNvZGUgc2VxdWVuY2VzIGhhdmUgYmVlbiBhY2N1bXVsYXRlZCBpbiB0aGUgQmFyY29kZSBvZiBMaWZlIERhdGFiYXNlLCBtYWtpbmcgaXQgYSB1c2VmdWwgcmVzb3VyY2UgZm9yIGVjb2xvZ3kgcmVzZWFyY2guCgpTcGlkZXIgZGl2ZXJzaXR5IGdlbmVyYWxseSBkZWNyZWFzZXMgd2l0aCBkaXN0YW5jZSBmcm9tIHRoZSBlcXVhdG9yIFtAUGllbDIwMThdLiBUaGVyZSBpcyBzb21lIGRlYmF0ZSBhcyB0byB3aGV0aGVyIHRoZSBkaXN0cmlidXRpb24gaXMgZXZlbiBiZXR3ZWVuIGhlbWlzcGhlcmVzIG9yIHBlYXItc2hhcGVkIHdpdGggdGhlIHNvdXRoZXJuIGhlbWlzcGhlcmUgYmVpbmcgbW9yZSBkaXZlcnNlLiBJbiB0aGlzIHdvcmssIEkgZXhhbWluZWQgd2hldGhlciB0aGUgY29sbGVjdGlvbiBvZiBETkEtYmFyY29kZWQgc3BpZGVyIHNwZWNpbWVucyBpbiB0aGUgQk9MRCBkYXRhYmFzZSBzaG93cyB0aGUgZGl2ZXJzaXR5IHRyZW5kIGFjcm9zcyBsYXRpdHVkZXMgYXMgaXMgcmVwb3J0ZWQgaW4gdGhlIGxpdGVyYXR1cmUuIEFkZGl0aW9uYWxseSwgc2FtcGxpbmcgZGVwdGggYW5kIGdlb2dyYXBoaWMgYmlhcyBvZiB0aGUgQk9MRCBkYXRhIHdlcmUgZXZhbHVhdGVkLgoKLS0tLS0KICAKIyBBbmFseXNpcyBhbmQgUmVzdWx0cwoKCiMjIyBTb2Z0d2FyZS9MaWJyYXJpZXMKClRoaXMgd29yayB3YXMgcHJvZHVjZWQgd2l0aCB0aGUgUiBsYW5ndWFnZSBhbmQgdGhlIGZvbGxvd2luZyBwYWNrYWdlczoKCmBgYHtyIHBja2dzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjYWNoZT1UUlVFfQojIHBhY2thZ2VzIHVzZWQKbGlicmFyeShib2xkKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnZ3RoZW1lcykKbGlicmFyeSh2ZWdhbikKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkobGVhZmxldCkKbGlicmFyeShndCkKbGlicmFyeShrYWJsZUV4dHJhKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KHJjYXJ0b2NvbG9yKQpsaWJyYXJ5KGlncmFwaCkKbGlicmFyeShwbG90bHkpCmBgYAo8YnI+CgotLS0tCgojIyMgRG93bmxvYWRpbmcgQk9MRCBzcGVjaW1lbiByZWNvcmRzCgpBbGwgc3BlY2ltZW4gcmVjb3JkcyBmb3IgKkFyYW5lYWUqIHdlcmUgZG93bmxvYWRlZCBmcm9tIHRoZSBCT0xEIGFwaSBvbiAyMDIwLTA5LTI5LiAKSSBhbHNvIG9idGFpbmVkIHRoZSBXb3JsZCBzcGlkZXIgY2F0YWxvZyBkYXRhc2V0IChvbiB0aGUgc2FtZSBkYXRlKSBhcyBhIHJlZmVyZW5jZSBmb3IgY29tcGFyaXNvbiBvZiB0YXhvbm9taWMgaWRlbnRpZmllcnMuCgoKYGBge3IgZG93bmxvYWQsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNhY2hlPVRSVUV9CiMjIGJ1aWxkIHRoZSB1cmwgZm9yIGRvd25sb2FkaW5nCiMgdGF4b24gPC0gIkFyYW5lYWUiCiMgdGF4b24gPC0gcGFzdGUwKCJ0YXhvbj0iLCB0YXhvbikKIyBwcmVmaXggPC0gImh0dHA6Ly93d3cuYm9sZHN5c3RlbXMub3JnL2luZGV4LnBocC9BUElfUHVibGljL3NwZWNpbWVuPyIKIyBmbXQgPC0gIiZmb3JtYXQ9dHN2IgojIHVybCA8LSBwYXN0ZTAocHJlZml4LCB0YXhvbiwgZm10KQojIAojICMgZG93bmxvYWQsIHBhcnNlIGRhdGEKIyBBcmFuZWFlLmRmIDwtIHJlYWRfZGVsaW0odXJsLCBkZWxpbSA9ICdcdCcsZ3Vlc3NfbWF4ID0gMTAwMDApCiMgd3JpdGVfcmRzKEFyYW5lYWUuZGYsICIuL2RhdGEvQk9MRC5hcmFuZWFlLnJkcyIpCiMgCmBgYAoKCi0tLS0tCgojIyMgQk9MRCAnQXJhbmFlYScgZGF0YXNldAoKVGhlIGRhdGFzZXQgdXNlZCBpbiB0aGlzIGFuYWx5c2lzIGNvbnRhaW5lZCBhbGwgdGhlIGF2YWlsYWJsZSBzcGVjaW1lbiByZWNvcmRzIG9mIHRoZSBvcmRlciAqQXJhY2VhZSouIApBbnkgcmVjb3JkcyBsYWNraW5nIEJJTiBpZGVudGlmaWVycyBvciBnZW9ncmFwaGljIG1ldGFkYXRhIHdlcmUgcmVtb3ZlZC4gClRoZXJlIGFyZSA5NSw0Nzkgc3BlY2ltZW4gcmVjb3JkcyBpbiB0aGlzIHNlbGVjdGlvbiwgcmVwcmVzZW50aW5nIDksNzU3IEJJTiBjbHVzdGVycyBhbmQgdGhlc2Ugd2VyZSBjb2xsZWN0ZWQgaW4gMTM2IGNvdW50cmllcy4KU3BlY2ltZW4gcmVjb3JkcyB3ZXJlIGdyb3VwZWQgYnkgYWJzb2x1dGUgbGF0aXR1ZGUgYW5kIGNsYXNzaWZpZWQgYXMgdHJvcGljYWwgKDAtMjDLmiksIHN1Yi10cm9waWNhbCAoMjAtNDDLmiksIHRlbXBlcmF0ZSAoNDAtNjDLmiksIG9yIGV4dHJlbWUgKDYwLTkwy5opLiAKU2ltaWxhcmx5LCBjb3VudHJpZXMgd2VyZSBncm91cGVkIGJ5IHRoZWlyIG1lYW4gbGF0aXR1ZGUgb2YgYWxsIHNwZWNpbWVucyBmb3IgZGl2ZXJzaXR5IGFuYWx5c2VzLgoKCmBgYHtyIHByb2Nlc3NpbmcsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNhY2hlPVRSVUV9CiMgcmVhZCBpbiBwcmV2aW91c2x5IGRvd25sb2FkZWQgZGF0YSBzZXRzCiMgU3BpZGVyX2NhdGFsb2cuZGYgPC0gcmVhZF9yZHMoIi4vZGF0YS9zcGlkZXJfY2F0YWxvZy5yZHMiKQpBcmFuZWFlLnJhdyA8LSByZWFkX3JkcygiLi9kYXRhL0JPTEQuYXJhbmVhZS5yZHMiKQoKIyB0aWR5IHVwIGRhdGEgYW5kIHJlbW92ZSB0aG9zZSBtaXNzaW5nIGNvdW50cnkgb3IgYmluIGRhdGEKQXJhbmVhZS5kZiA8LSBBcmFuZWFlLnJhdyAlPiUKICAjIEtlZXAgb25seSB1c2VmdWwgZGF0YSBjb2x1bW5zCiAgc2VsZWN0KHJlY29yZElELCBiaW5fdXJpLCBmYW1pbHlfbmFtZSwgZ2VudXNfbmFtZSwgc3BlY2llc19uYW1lLAogICAgICAgICBjb3VudHJ5LCBwcm92aW5jZV9zdGF0ZSwgbGF0LCBsb24sIGVsZXYpICAlPiUKICAjIEV4Y2x1ZGUgYW55IHJlY29yZCB0aGF0IGlzIG1pc3NpbmcgQklOIG9yIENvdW50cnkgbGFiZWxzCiAgZmlsdGVyKCFpcy5uYShiaW5fdXJpKSAmICFpcy5uYShjb3VudHJ5KSkgICU+JQogICMgQW55IG1pc3NpbmcgdGF4b25vbWljIGxhYmVscyBhcmUgcmVwbGFjZWQgd2l0aCAnVW5rbm93bicKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLmNoYXJhY3RlciksIH5hcy5mYWN0b3IocmVwbGFjZV9uYSgueCwgJ1Vua25vd24nKSkpKSAlPiUKICAjIENyZWF0ZSBuZXcgdmFyaWFibGUgdG8gZ3JvdXAgcmVjb3JkcyBieSBjbGltYXRlIHpvbmUKICBtdXRhdGUoem9uZSA9IGFzLmZhY3RvcihjYXNlX3doZW4oCiAgICBhYnMobGF0KSA8PSAyMCB+ICdUcm9waWNhbCcsCiAgICBhYnMobGF0KSA+IDIxICYgYWJzKGxhdCkgPD0gNDAgIH4gJ1N1Yi10cm9waWNhbCcsCiAgICBhYnMobGF0KSA+IDQwICYgYWJzKGxhdCkgPD0gNjAgIH4gJ1RlbXBlcmF0ZScsCiAgICBhYnMobGF0KSA+IDYwIH4gJ0V4dHJlbWUnLAogICkpCiAgKQoKIyBBc3NpZ25pbmcgY291bnRyaWVzIHRvIGxhdGl0dWRlIHpvbmVzIGJhc2VkIG9uIG1lYW4gbGF0aXR1ZGUKY291bnRyeV96b25lcyA8LSBBcmFuZWFlLmRmICU+JQogIGdyb3VwX2J5KGNvdW50cnkpICU+JQogIHN1bW1hcmlzZShsYXQubWVhbiA9IG1lYW4obGF0LCBuYS5ybSA9IFRSVUUpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKHpvbmUgPSBhcy5mYWN0b3IoY2FzZV93aGVuKAogICAgYWJzKGxhdC5tZWFuKSA8PSAyMCB+ICdUcm9waWNhbCcsCiAgICBhYnMobGF0Lm1lYW4pID4gMjAgJiBhYnMobGF0Lm1lYW4pIDw9IDQwICB+ICdTdWItdHJvcGljYWwnLAogICAgYWJzKGxhdC5tZWFuKSA+IDQwICYgYWJzKGxhdC5tZWFuKSA8PSA2MCAgfiAnVGVtcGVyYXRlJywKICAgIGFicyhsYXQubWVhbikgPiA2MCB+ICdFeHRyZW1lJywKICApKSkgJT4lCiAgIyBpZ25vcmUgYW55IGNvdW50cmllcyB0aGF0IHdlcmVuJ3QgbGFiZWxsZWQKICBmaWx0ZXIoIWlzLm5hKHpvbmUpKSAlPiUKICBtdXRhdGUoQ291bnRyeSA9IGNvdW50cnkpICU+JQogIHNlbGVjdChDb3VudHJ5LCBjb3VudHJ5LCB6b25lKQogIAojIGNvdW50cnlfem9uZXMKCiMgdGFibGUgb2YgYmFzaWMgc3RhdGlzdGljcyBhYm91dCBzcGVjaW1lbiByZWNvcmRzIGZyb20gQk9MRApkYXRhX3N1bW1hcnkgPC0gdGliYmxlKAogIENoYXJhY3RlcmlzdGljID0gYygKICAgICdTcGVjaW1lbiByZWNvcmRzIGluIEJPTEQnLAogICAgJ1JlY29yZHMgc2VsZWN0aW9uIChub3QgbWlzc2luZyBCSU4gYW5kIGNvdW50cnkgZGF0YSknLAogICAgJ051bWJlciBvZiB1bmlxdWUgQklOcyBpbiBzZWxlY3RlZCByZWNvcmRzJywKICAgICdVbmlxdWUgZmFtaWx5IHRheGEnLCAnVW5pcXVlIGdlbnVzIHRheGEnLCAnVW5pcXVlIHNwZWNpZXMgdGF4YScsCiAgICAnU291cmNlIGNvdW50cmllcyBpbiBzZWxlY3RlZCByZWNvcmRzJywKICAgICdMYXRpdHVkZSByYW5nZScpLAogIFZhbHVlID0gYygKICAgIGNvbW1hKG5yb3coQXJhbmVhZS5yYXcpKSwKICAgIGNvbW1hKG5yb3coQXJhbmVhZS5kZikpLAogICAgY29tbWEobGVuZ3RoKHVuaXF1ZShBcmFuZWFlLmRmJGJpbl91cmkpKSksCiAgICBsZW5ndGgodW5pcXVlKEFyYW5lYWUuZGYkZmFtaWx5X25hbWUpKSwKICAgIGNvbW1hKGxlbmd0aCh1bmlxdWUoQXJhbmVhZS5kZiRnZW51c19uYW1lKSkpLAogICAgY29tbWEobGVuZ3RoKHVuaXF1ZShBcmFuZWFlLmRmJHNwZWNpZXNfbmFtZSkpKSwKICAgIGxlbmd0aCh1bmlxdWUoQXJhbmVhZS5kZiRjb3VudHJ5KSksCiAgICBwYXN0ZTAocm91bmQobWluKEFyYW5lYWUuZGYkbGF0LCBuYS5ybSA9IFRSVUUpLCAxKSwKICAgICAgICAgICAnIDogJywgcm91bmQobWF4KEFyYW5lYWUuZGYkbGF0LCBuYS5ybSA9IFRSVUUpLCAxKSkKICApKQoKIyB0YWJ1bGF0ZSBuIHNwZWNpbWVucyBhbmQgc3BlY2llcyBieSBjb3VudHJ5IGZvciBhcnJhbmdpbmcgY291bnRyaWVzIGJ5IG4gc3BlY2ltZW5zIGFuZCBiaW5zCmNvdW50cnkuc3BlY2ltZW5zLnRhYmxlIDwtIEFyYW5lYWUuZGYgJT4lCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lCiAgc3VtbWFyaXplKHNwZWNpbWVucyA9IG4oKSwKICAgICAgICAgICAgc3BlY2llcyA9IGxlbmd0aCh1bmlxdWUoYmluX3VyaSkpKSAlPiUKICBhcnJhbmdlKGRlc2Moc3BlY2llcykpICU+JQogIGxlZnRfam9pbihjb3VudHJ5X3pvbmVzICU+JSBzZWxlY3QoY291bnRyeSwgem9uZSkpCgpgYGAKIApcaGZpbGxcYnJlYWsgIAoKKipUYWJsZSAxKiouIFN1bW1hcnkgb2YgKkFyYW5lYWUqIHNwZWNpbWVuIHJlY29yZHMgZnJvbSB0aGUgQk9MRCBkYXRhYmFzZSB0aGF0IHdlcmUgdXNlZCBpbiB0aGlzIGFuYWx5c2lzLiAKICAgICAKYGBge3Igc3VtbWFyeS50YWJsZSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2FjaGU9VFJVRX0Ka2FibGUoZGF0YV9zdW1tYXJ5LCBmb3JtYXQgPSAncGlwZScsZXNjYXBlID0gVFJVRSkKYGBgCiAKLS0tLS0KCiMjIyBTcGVjaW1lbiBNYXAKCkEgbWFwIHNob3dpbmcgdGhlIGdlb2dyYXBoaWMgZGlzdHJpYnV0aW9uIG9mIHNwaWRlciBzcGVjaW1lbnMgaW4gdGhlIEJPTEQgZGF0YWJhc2UuIFN0cm9uZyBOb3J0aCBBbWVyaWNhbiBhbmQgRXVyb3BlYW4gc2FtcGxpbmcgYmlhcyBpcyBldmlkZW50OyB0aGUgU291dGhlcm4gaGVtaXNwaGVyZSBpcyBub3Qgd2VsbCByZXByZXNlbnRlZCwgZXNwZWNpYWxseSBBZnJpY2EgYW5kIENlbnRyYWwgQXNpYS4KICAgCmBgYHtyIHNwaWRlci5tYXAsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNhY2hlPVRSVUV9CiMjIGdyb3VwIHNwZWNpbWVucyBvbiBhIDFkZWcgZ3JpZApzcGlkZXIubWFwLmRmIDwtIEFyYW5lYWUuZGYgJT4lCiAgIyByb3VuZCBjb29yZHMgdG8gbmVhcmVzdCBkZWcuCiAgbXV0YXRlKGxhdCA9IHJvdW5kKGxhdCksCiAgICAgICAgIGxvbiA9IHJvdW5kKGxvbikpICU+JQogICMgZ3JvdXAvY291bnQgYWxsIHNwZWNpbWVucyB3aXRoIHNhbWUgY29vcmRzCiAgZ3JvdXBfYnkobGF0LCBsb24pICU+JQogIG11dGF0ZShuPW4oKSwKICAgICAgICAgQklOcyA9IGxlbmd0aCh1bmlxdWUoYmluX3VyaSkpKSAlPiUKICBzZWxlY3QobGF0LCBsb24sIG4sIEJJTnMpICU+JQogIGRpc3RpbmN0KCkgJT4lCiAgIyBjcmVhdGUgcG9wdXAgbGFiZWxzIHdpdGggaW5mbwogIG11dGF0ZShwb3B1cHMgPSBwYXN0ZTAoCiAgICAiPGI+TGF0OiA8L2I+IiwgbGF0LAogICAgJzxicj48Yj5Mb25nOiA8L2I+JywgbG9uLAogICAgIjxicj48Yj5TcGVjaW1lbnM6IDwvYj4iLCBuLAogICAgIjxicj48Yj5CSU5zOiA8L2I+IiwgQklOcyksCiAgICBsYWJzID0gcGFzdGUobiwgJ3NwZWNpbWVucycpCiAgICApICU+JQogIGZpbHRlcighKGlzLm5hKGxhdCl8aXMubmEobG9uKSkpCgoKIyBjcmVhdGUgbWFwCgptYWtlLnNwaWRlci5tYXAgPC0gZnVuY3Rpb24oc3BpZGVyLm1hcC5kZil7CiAgCiAgc3BpZGVyLm1hcCA8LSBsZWFmbGV0KHNwaWRlci5tYXAuZGYpICU+JQogICAgc2V0Vmlldyh6b29tPTEsIGxhdD0zMCwgbG5nPTUpICU+JQogICAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgCiAgCiAgIyBhZGQgbGF0aXR1ZGUgbGluZXMgdGhhdCBzYW1wbGVzIHdlcmUgZ3JvdXBlZCBieQogIGZvciAoaSBpbiBjKC02MCwgLTQwLCAtMjAsIDAsIDIwLCA0MCwgNjApKSB7CiAgICBzcGlkZXIubWFwIDwtIHNwaWRlci5tYXAgJT4lCiAgICAgIGFkZFBvbHlsaW5lcyhsbmcgPSBjKC0zNjA6MzYwLCAzNjA6LTM2MCksIAogICAgICAgICAgICAgICAgICAgbGF0ID0gcmVwKGksIHRpbWVzPTcyMCksIHdlaWdodCA9IDAuNCkKICB9CiAgCiAgc3BpZGVyLm1hcCA8LSBzcGlkZXIubWFwICU+JQogICAgYWRkQ2lyY2xlTWFya2VycygKICAgICAgY29sb3IgPSAnI2YyMDAwMCcsCiAgICAgIGxuZyA9IH5sb24sCiAgICAgIGxhdCA9IH5sYXQsCiAgICAgIHJhZGl1cyA9IH4obG9nKG4pKzEpKjAuNCwKICAgICAgZmlsbE9wYWNpdHkgPSAwLjMsCiAgICAgIHN0cm9rZSA9IEZBTFNFLAogICAgICBwb3B1cCA9IH5wb3B1cHMsCiAgICAgIGxhYmVsID0gfmxhYnMKICAgICkgIAogIHJldHVybihzcGlkZXIubWFwKQp9CgptYWtlLnNwaWRlci5tYXAoc3BpZGVyLm1hcC5kZikKYGBgCgoqKkZpZ3VyZSAxLiBHZW9ncmFwaHkgb2YgQk9MRCBzcGlkZXIgc3BlY2ltZW5zKiouIE1hcmtlcnMgc2hvdyB0aGUgbG9jYXRpb24gYW5kIGFtb3VudCBvZiBzcGVjaW1lbnMgY29sbGVjdGVkIGF0IGVhY2ggbG9jYXRpb247IHNwZWNpbWVucyB3ZXJlIGJpbm5lZCBpbnRvIGEgMWRlZyB4IDFkZWcgZ3JpZCBmb3IgY291bnRpbmcuIExhdGl0dWRlIGxpbmVzIGNvcnJlc3BvbmQgdG8gdGhlIHpvbmVzIHRoYXQgd2VyZSBjb25zaWRlcmVkIGluIHRoZSBnZW9ncmFwaGljIGFuYWx5c2lzIG9mIHNwaWRlciBkaXZlcnNpdHkuICooQW4gaW50ZXJhY3RpdmUgdmVyc2lvbiB3aXRoIHpvb20gJiBsYWJlbHMgaXMgcHJlc2VudGVkIGluIHRoZSBhY2NvbXBhbnlpbmcgaHRtbC1ub3RlYm9vayAnSk1vZ2dfc3BpZGVyX2RpdmVyc2l0eV9ub3RlYm9vay5odG1sJykqCgogICAgCiMjIyBDb21wb3NpdGlvbiBhbmQgc2FtcGxpbmcgZGVwdGggYnkgbGF0aXR1ZGUKCmBgYHtyIGJhcl9mYW1pbGllcywgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9NywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2FjaGU9VFJVRX0KIyB0YWJsdWxhdGUgc3BlY2ltZW4gcmVjb3JkcyBjb3VudCBieSBCSU4KYmluLnRhYmxlIDwtIEFyYW5lYWUuZGYgJT4lCiAgY291bnQoYmluX3VyaSkKCiMgcGxvdCBoaXN0b2dyYW0gb2Ygc3BlY2ltZW4gY291bnRzIGZvciBCSU5zIChiaW4gc2l6ZSBkaXN0cmlidXRpb24pCgpiaW4uaGlzdCA8LSBiaW4udGFibGUgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbikpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTAwKSArCiAgc2NhbGVfeF9sb2cxMCgpICsgc2NhbGVfeV9sb2cxMCgpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZCgpICsKICBsYWJzKHggPSAnU3BlY2ltZW5zIGFzc2lnbmVkIHRvIEJJTicsCiAgICAgICB5ID0gJ0ZyZXF1ZW5jeScpICsKICB0aGVtZV9jbGFzc2ljKCkKICAKIyBBcmFuZWFlLmRmMiA8LSBBcmFuZWFlLmRmICU+JQojICAgbXV0YXRlKHBsb3RseS5sYWJzID0gcGFzdGUoIjxiPkxhdDo8L2I+IiwgbGF0LAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzxicj48Yj5GYW1pbHk8L2I+OiwgZmFtaWx5X25hbWUpKQojIFNwZWNpbWVuIGRpc3RyaWJ1dGlvbiBieSBsYXRpdHVkZQpzcGVjLmxhdHMuYmFyIDwtIGdncGxvdChBcmFuZWFlLmRmLCBhZXMoeT1sYXQsIGZpbGwgPSBmYW1pbHlfbmFtZSkpICsKICBnZW9tX2hpc3RvZ3JhbShhbHBoYSA9IDAuOCwgY29sb3VyID0gJ2xpZ2h0Z3JleScsIG9yaWVudGF0aW9uID0gJ3knLAogICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZChvcHRpb24gPSAnQycpICsKICBsYWJzKHkgPSAnTGF0aXR1ZGUnLCB4ID0gJ1NwZWNpbWVuIGNvdW50JykgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ251bGwnKQoKIyBzaG93IGJvdGggcGxvdHMKCmdncGxvdGx5KHNwZWMubGF0cy5iYXIpCmBgYAoKKipGaWd1cmUgMmEuKiogQSBwbG90IHNob3dpbmcgdGhlIG51bWJlciBvZiBzYW1wbGVzIGNvbGxlY3RlZCBieSBsYXRpdHVkZTsgY29sb3JzIGNvcnJlc3BvbmQgdG8gZGlmZmVyZW50IHNwaWRlciBmYW1pbGllczsgcG9wdXAgbGFiZWxzIHNob3cgZmFtaWx5IG5hbWUgYW5kIHNwZWNpbWVuIGNvdW50IC0gcGxlYXNlIGlnbm9yZSBsYXRpdHVkZSBpbiBwb3B1cCBsYWJlbHMgYW5kIHJlYWQgZnJvbSB5LWF4aXMuIEZhbWlsaWVzIGNhbiBiZSBoaWRkZW4vcmV2ZWFsZWQgYnkgY2xpY2tpbmcgaWNvbnMgb24gdGhlIGxlZ2VuZCAoc2Nyb2xsIHRvIGJyb3dzZSkuCgpgYGB7ciBiaW4uIGhpc3QsIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2FjaGU9VFJVRX0KYmluLmhpc3QKYGBgCiAgICAKICAgIAoKCioqRmlndXJlIDJiLioqICBBIGhpc3RvZ3JhbSBzaG93aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIG51bWJlciBvZiBzcGVjaW1lbnMgdGhhdCBoYXZlIGJlZW4gYXNzaWduZWQgdG8gZWFjaCBCSU4uCiAgIAotLS0tLQoKCiMjIyBDb21tdW5pdHkgYWJ1bmRhbmNlcyAmIGFscGhhLWRpdmVyc2l0eSBhbmFseXNpcwoKQ29tbXVuaXR5IGFidW5kYW5jZSB0YWJsZXMgd2VyZSBjcmVhdGVkIGZvciB0aGUgZW50aXJlIGRhdGFzZXQsIGJ5IGNvdW50cnkgYW5kIGJ5IGxhdGl0dWRlIHpvbmUgZm9yIGRpdmVyc2l0eSBhbmFseXNlcyB3aXRoIHRoZSBgdmVnYW5gIHBhY2thZ2UuCgoKYGBge3IgY29tbXVuLmFidW5kLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjYWNoZT1UUlVFfQojICMgY3JlYXRpbmcgY29tbXVuaXR5IGFidW5kYW5jZSBtYXRyaWNlcyBmb3IgdmVnYW4gZnVuY3Rpb25zCiMgIyBNYWtlIHRhYmxlcyB3aXRoIGJpbnMgYXMgY29sdW1ucyArIHJlcGxhY2UgbWlzc2luZyB2YWx1ZXMgd2l0aCB6ZXJvZXMKIyAKIyAjIEJpbiBjb3VudHMgZnJvbSBmdWxsIGRhdGFzZXQKIyBBcmFuZWFlLmRmLmJpbnMgPC0gQXJhbmVhZS5kZiAlPiUKIyAgICMgY291bnQgc3BlY2ltZW5zCiMgICBjb3VudChiaW5fdXJpKSAlPiUKIyAgICMgbWFrZSB3aWRlIHRhYmxlCiMgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYmluX3VyaSwgdmFsdWVzX2Zyb20gPSBuKQojIHdyaXRlX3JkcyhBcmFuZWFlLmRmLmJpbnMsICIuL2RhdGEvQXJhbmVhZS5iaW5zLnJkcyIpCiMgCiMgIyBjb21tdW5pdHkgbWF0cml4IHdpdGggY291bnRyaWVzIGFzIG9ic2VydmF0aW9ucyAKIyAjIG11c3QgbWFrZSBzaXRlIGludG8gcm93bmFtZXMKIyBBcmFuZWFlLmNvdW50cnkuYmlucyA8LSBBcmFuZWFlLmRmICU+JQojICAgY291bnQoYmluX3VyaSwgY291bnRyeSkgJT4lCiMgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYmluX3VyaSwgdmFsdWVzX2Zyb20gPSBuKSAlPiUKIyAgICMgcmVwbGFjZSBOQSB3aXRoIDAgdmFsdWVzCiMgICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+cmVwbGFjZV9uYSgueCwgMCkpKSAgJT4lCiMgICAjIG1ha2Ugc2l0ZSBsYWJlbHMgaW50byBkZiByb3duYW1lcwojICAgcmVtb3ZlX3Jvd25hbWVzICU+JQojICAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJjb3VudHJ5IikKIyB3cml0ZV9yZHMoQXJhbmVhZS5jb3VudHJ5LmJpbnMsICIuL2RhdGEvQXJhbmVhZS5jb3VudHJ5LmJpbnMucmRzIikKIyAKIyAjIGNvbW11bml0eSBtYXRyaXggd2l0aCBsYXRpdHVkZSB6b25lcyBhcyBvYnNlcnZhdGlvbnMKIyBBcmFuZWFlLnpvbmUuYmlucyA8LSBBcmFuZWFlLmRmICU+JQojICAgY291bnQoYmluX3VyaSwgem9uZSkgJT4lCiMgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYmluX3VyaSwgdmFsdWVzX2Zyb20gPSBuKSAlPiUKIyAgIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIH5yZXBsYWNlX25hKC54LCAwKSkpICU+JQojICAgZmlsdGVyKCFpcy5uYSh6b25lKSkgJT4lCiMgICByZW1vdmVfcm93bmFtZXMgJT4lCiMgICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gInpvbmUiKQojIHdyaXRlX3JkcyhBcmFuZWFlLnpvbmUuYmlucywgIi4vZGF0YS9BcmFuZWFlLnpvbmUuYmlucy5yZHMiKQpgYGAKCgoKClJpY2huZXNzIG9mIEJJTnMgYW5kIHJhcmVmaWVkIHJpY2huZXNzIChzYW1wbGU9NTAwKSwgU2hhbm5vbiBkaXZlcnNpdHksIGFuZCBTaW1wc29uIGRpdmVyc2l0eSB3ZXJlIGNhbGN1bGF0ZWQgZm9yIGVhY2ggY291bnRyeSBhbmQgZWFjaCBsYXRpdHVkZSB6b25lcy4KCgpgYGB7ciBhbHBoYSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2FjaGU9VFJVRX0KIyBjb21tdW5pdHkgYWJ1bmRhbmNlIG1hdHJpY2VzIG1hZGUgaW4gcHJldmlvdXMgY29kZSBjaHVuawpBcmFuZWFlLmJpbnMgPC0gcmVhZF9yZHMoIi4vZGF0YS9BcmFuZWFlLmJpbnMucmRzIikKQXJhbmVhZS56b25lLmJpbnMgPC0gcmVhZF9yZHMoIi4vZGF0YS9BcmFuZWFlLnpvbmUuYmlucy5yZHMiKQpBcmFuZWFlLmNvdW50cnkuYmlucyA8LSByZWFkX3JkcygiLi9kYXRhL0FyYW5lYWUuY291bnRyeS5iaW5zLnJkcyIpCgpjb3VudHJ5LmJpbnMuNTAwIDwtIEFyYW5lYWUuY291bnRyeS5iaW5zICU+JQogIGJpbmRfY29scyhzdW0gPSByb3dTdW1zKEFyYW5lYWUuY291bnRyeS5iaW5zKSkgJT4lCiAgZmlsdGVyKHN1bSA+IDUwMCkgJT4lCiAgc2VsZWN0KC1zdW0pCgojIGNhbGN1bGF0ZSByaWNobmVzcyAmIGFscGhhIGRpdmVyc2l0eSBtZXRyaWNzIGZvciBlYWNoIGNvdW50cnkKYWxwaGEuZGl2ZXJzaXR5LmNvdW50cnkgPC0gZGF0YS5mcmFtZShDb3VudHJ5PXJvd25hbWVzKGNvdW50cnkuYmlucy41MDApKSAlPiUKICBiaW5kX2NvbHMoCiAgICBsaXN0KAogICAgICBTcGVjaW1lbnMgPSByb3dTdW1zKGNvdW50cnkuYmlucy41MDApLAogICAgICBSaWNobmVzcyA9IHJvd1N1bXMoY291bnRyeS5iaW5zLjUwMCA+IDApLAogICAgICBgUmFyZWZpZWRgID0gdmVnYW46OnJhcmVmeShjb3VudHJ5LmJpbnMuNTAwLCBzYW1wbGUgPSA1MDApLAogICAgICBTaGFubm9uID0gdmVnYW46OmRpdmVyc2l0eShjb3VudHJ5LmJpbnMuNTAwLCBpbmRleCA9ICdzaGFubm9uJyksCiAgICAgIFNpbXBzb24gPSB2ZWdhbjo6ZGl2ZXJzaXR5KGNvdW50cnkuYmlucy41MDAsIGluZGV4ID0gJ3NpbXBzb24nKQogICAgKQogICAgKSAlPiUKICAjIHJvdW5kIG51bWJlcnMgb2ZmIHRvIDIgZGVjaW1hbHMKICBtdXRhdGUoU2hhbm5vbiA9IHJvdW5kKFNoYW5ub24sIDIpLAogICAgICAgICBTaW1wc29uID0gcm91bmQoU2ltcHNvbiwgMikpICU+JQogIGFycmFuZ2UoZGVzYyhTcGVjaW1lbnMpKSAlPiUKICBsZWZ0X2pvaW4oY291bnRyeV96b25lcyAlPiUgc2VsZWN0KC1jb3VudHJ5KSwgYnkgPSAnQ291bnRyeScpCgojIGthYmxlKGFscGhhLmRpdmVyc2l0eS5jb3VudHJ5LCBmb3JtYXQgPSAnc2ltcGxlJykKCnJpY2hfc3BlY2llc19sbSA8LSBnZ3Bsb3QoYWxwaGEuZGl2ZXJzaXR5LmNvdW50cnksIAogICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyh4PWxvZyhTcGVjaW1lbnMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZyhSaWNobmVzcykpKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gbG0pICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHpvbmUpKSArCiAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IENvdW50cnksIGNvbG9yID0gem9uZSkpICsKICBzY2FsZV9jb2xvcl9kaXNjcmV0ZSgiTGF0LiB6b25lIikgKwogIHRoZW1lX2NsYXNzaWMoKQojIHJpY2hfc3BlY2llc19sbQoKIyMjIyMjIyMjIwoKIyBhcnJhbmdpbmcgbGFiZWxzIGZvciBwbG90IGJlbG93IChsZXhpY28gc29ydCB5LWF4aXMgY291bnRyaWVzKSAgICAKYWxwaGEuZGl2ZXJzaXR5LmNvdW50cnkkQ291bnRyeSA8LSBmYWN0b3IoYWxwaGEuZGl2ZXJzaXR5LmNvdW50cnkkQ291bnRyeSwgbGV2ZWxzPXJldihzb3J0KGFscGhhLmRpdmVyc2l0eS5jb3VudHJ5JENvdW50cnkpKSkKCiMgYXJyYW5naW5nIGRhdGEgdG8gbG9uZyBmb3JtIHdpdGggZGl2ZXJzaXR5IGluZGljZSArIHZhbHVlIHJvd3MgZm9yIGVhIGNvdW50cnkKYWxwaGEuY291bnRyeS5sb25nIDwtIGFscGhhLmRpdmVyc2l0eS5jb3VudHJ5ICU+JQogIHBpdm90X2xvbmdlcihSYXJlZmllZDpTaW1wc29uKSAlPiUKICBhcnJhbmdlKGRlc2MoQ291bnRyeSkpIAoKIyByZWFycmFuZ2UgZ3JpZCBjb2x1bW5zIGZvciBwbG90IGJ5IGNoYW5naW5nIGxldmVscwphbHBoYS5jb3VudHJ5LmxvbmckbmFtZSA8LSBmYWN0b3IoYWxwaGEuY291bnRyeS5sb25nJG5hbWUsIGxldmVscyA9IGMoIlJpY2huZXNzIiwgIlJhcmVmaWVkIiwiU2hhbm5vbiIsICJTaW1wc29uIikpCmFscGhhLmNvdW50cnkubG9uZyR6b25lIDwtIGZhY3RvcihhbHBoYS5jb3VudHJ5Lmxvbmckem9uZSwgbGV2ZWxzID0gYygiRXh0cmVtZSIsICJUZW1wZXJhdGUiLCJTdWItdHJvcGljYWwiLCAiVHJvcGljYWwiKSkKCiMgZ3JpZCBwbG90IG9mIGRpdmVyc2l0eSBpbmRpY2VzCmRpdmVyc2l0eS5wbG90IDwtIGdncGxvdChhbHBoYS5jb3VudHJ5LmxvbmcsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeSA9IENvdW50cnksIHggPSB2YWx1ZSwgY29sb3VyID0gem9uZSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHhlbmQgPSB2YWx1ZSwgeWVuZCA9IENvdW50cnkpKSArCiAgZmFjZXRfZ3JpZCh+bmFtZSwgc2NhbGVzID0gJ2ZyZWUnKSArCiAgbGFicyh4ID0gJycsIHk9JycpICsKICBzY2FsZV9jb2xvcl9kaXNjcmV0ZSgiTGF0LiB6b25lIikgKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUoIkxhdC4gem9uZSIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gJ251bGwnLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIHZqdXN0ID0gMCkpCgojIyMjIyMjIwoKIyBjYWxjdWxhdGUgcmljaG5lc3MgJiBhbHBoYSBkaXZlcnNpdHkgbWV0cmljcyBmb3IgbGF0aXR1ZGUgem9uZXMKYWxwaGEuZGl2ZXJzaXR5LnpvbmVzIDwtIGRhdGEuZnJhbWUoWm9uZT1yb3duYW1lcyhBcmFuZWFlLnpvbmUuYmlucykpICU+JQogICMgYmluZCBhIG5ldyBjb2x1bW4gZm9yIGVhY2ggc3RhdGlzdGljCiAgYmluZF9jb2xzKAogICAgbGlzdCgKICAgICAgYFJhbmdlIChhYnMuIGRlZylgID0gcmV2KGMoJzAtMjAnLCAnMjAtNDAnLCc0MC02MCcsICc2MCsnKSksCiAgICAgIG4gPSByb3dTdW1zKEFyYW5lYWUuem9uZS5iaW5zKSwKICAgICAgUmljaG5lc3MgPSByb3dTdW1zKEFyYW5lYWUuem9uZS5iaW5zID4gMCksCiAgICAgIGBSYXJlZmllZGAgPSB2ZWdhbjo6cmFyZWZ5KEFyYW5lYWUuem9uZS5iaW5zLCBzYW1wbGUgPSA1MDApLAogICAgICBTaGFubm9uID0gdmVnYW46OmRpdmVyc2l0eShBcmFuZWFlLnpvbmUuYmlucywgaW5kZXggPSAnc2hhbm5vbicpLAogICAgICBTaW1wc29uID0gdmVnYW46OmRpdmVyc2l0eShBcmFuZWFlLnpvbmUuYmlucywgaW5kZXggPSAnc2ltcHNvbicpCiAgICApCiAgKSAlPiUKICBtdXRhdGUoU2hhbm5vbiA9IHJvdW5kKFNoYW5ub24sIDIpLAogICAgICAgICBTaW1wc29uID0gcm91bmQoU2ltcHNvbiwgMiksCiAgICAgICAgIGBSYXJlZmllZGAgPSByb3VuZChgUmFyZWZpZWRgKSkKCiMjIyMjIyMKCiMgYXJyYW5naW5nIGxhYmVscyBmb3IgcGxvdCBiZWxvdyAobGV4aWNvIHNvcnQgeS1heGlzIHpvbmVzKSAgICAKYWxwaGEuZGl2ZXJzaXR5LnpvbmVzJFpvbmUgPC0gZmFjdG9yKGFscGhhLmRpdmVyc2l0eS56b25lcyRab25lLCBsZXZlbHM9cmV2KHNvcnQoYWxwaGEuZGl2ZXJzaXR5LnpvbmVzJFpvbmUpKSkKCiMgYXJyYW5naW5nIGRhdGEgdG8gbG9uZyBmb3JtIHdpdGggZGl2ZXJzaXR5IGluZGljZSArIHZhbHVlIHJvd3MgZm9yIGVhIGNvdW50cnkKYWxwaGEuem9uZXMubG9uZyA8LSBhbHBoYS5kaXZlcnNpdHkuem9uZXMgJT4lCiAgcGl2b3RfbG9uZ2VyKFJhcmVmaWVkOlNpbXBzb24pICU+JQogIGFycmFuZ2UoZGVzYyhab25lKSkgCgojIHJlYXJyYW5nZSBncmlkIHJvd3MsIGNvbHVtbnMgZm9yIHBsb3QKYWxwaGEuem9uZXMubG9uZyRab25lIDwtIGZhY3RvcihhbHBoYS56b25lcy5sb25nJFpvbmUsIGxldmVscyA9IGMoIkV4dHJlbWUiLCAiVGVtcGVyYXRlIiwiU3ViLXRyb3BpY2FsIiwgIlRyb3BpY2FsIikpCgphbHBoYS56b25lcy5sb25nJG5hbWUgPC0gZmFjdG9yKGFscGhhLnpvbmVzLmxvbmckbmFtZSwgbGV2ZWxzID0gYygiUmljaG5lc3MiLCAiUmFyZWZpZWQiLCJTaGFubm9uIiwgIlNpbXBzb24iKSkKCgojIGdyaWQgcGxvdCBvZiBkaXZlcnNpdHkgaW5kaWNlcwpkaXZlcnNpdHkucGxvdC56b25lIDwtIGdncGxvdChhbHBoYS56b25lcy5sb25nLGFlcyh5ID0gWm9uZSwgeCA9IHZhbHVlLCBmaWxsID0gWm9uZSkpICsKICBnZW9tX2NvbCgpICsKICAjIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHhlbmQgPSB2YWx1ZSwgeWVuZCA9IFpvbmUpKSArCiAgZmFjZXRfZ3JpZCh+bmFtZSwgc2NhbGVzID0gJ2ZyZWUnKSArCiAgbGFicyh4ID0gJycsIHk9JycpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKCJMYXQuIHpvbmUiKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICAKICB0aGVtZShzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICdudWxsJykKCiMjIyMjIyMjIwoKYWxwaGEuem9uZXMuY291bnRyaWVzLnBsb3QgPC0gYWxwaGEuY291bnRyeS5sb25nICU+JQogIGdncGxvdChhZXMoeT16b25lLCB4ID0gdmFsdWUsIGNvbG91ciA9IHpvbmUpKSArCiAgZ2VvbV9ib3hwbG90KGNvbG91ciA9ICdncmF5ODAnLG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIGdlb21faml0dGVyKGFscGhhID0gMC45LCBwY2ggPSAwKSArCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgiTGF0LiB6b25lIikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFscGhhLnpvbmVzLmxvbmcsIGFlcyh5PVpvbmUsIHggPSB2YWx1ZSwgY29sb3VyID0gWm9uZSksIHNpemUgPSAyKSArCiAgZmFjZXRfZ3JpZCh+bmFtZSwgc2NhbGVzPSdmcmVlJykgKwogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKCJMYXQuIHpvbmUiKSArCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgiTGF0LiB6b25lIikgKwogIGxhYnMoeD0nJywgeT0nJykgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUoc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAnbnVsbCcsCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgdmp1c3QgPSAwKSkKCgpgYGAKICAKCioqVGFibGUgMi4qKiBSaWNobmVzcyBhbmQgZGl2ZXJzaXR5IG9mIHRoZSBCT0xEIHNwaWRlciBjb2xsZWN0aW9uIGluIGRpZmZlcmVudCBsYXRpdHVkZSB6b25lcyAoYmFzZWQgb24gYWJzb2x1dGUgZGlzdGFuY2UgZnJvbSB0aGUgZXF1YXRvcikuICAKICAgICAgCgpgYGB7ciB0YWJsZS5hbHBoYSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2FjaGU9VFJVRX0Ka2FibGUoYWxwaGEuZGl2ZXJzaXR5LnpvbmVzLCBmb3JtYXQgPSAncGlwZScpCmBgYAoKLS0tLQoKYGBge3IgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2FjaGU9VFJVRX0KcGF0Y2h3b3JrOjp3cmFwX3Bsb3RzKGFscGhhLnpvbmVzLmNvdW50cmllcy5wbG90L2RpdmVyc2l0eS5wbG90KQpgYGAKICAKKipGaWd1cmUgNC4qKiBSYXJlZmllZCByaWNobmVzcyAobj01MDApLCBTaGFubm9uIGRpdmVyc2l0eSwgYW5kIFNpbXBzb24gZGl2ZXJzaXR5IG9mIHNwaWRlciBzcGlkZXIgY29tbXVuaXRpZXMgaW4gbGF0aXR1ZGUgem9uZXMgKHRvcCkgYW5kIGNvdW50cmllcyAoYm90dG9tKS4gQ291bnRyaWVzIHdlcmUgYXNzaWduZWQgdG8gem9uZXMgYmFzZWQgb24gdGhlaXIgbWVhbiBzcGVjaW1lbiBsYXRpdHVkZS4gKnRvcCo6IEluIGVhY2ggcGFuZWwsIHRoZSB2YWx1ZXMgZm9yIGVhY2ggY291bnRyeSBpbiB0aGUgem9uZSBhcmUgc2hvd24gYXMgaG9sbG93IHNxdWFyZXMsIHdpdGggdGhlIGRpc3RyaWJ1dGlvbiBzaG93biBieSB0aGUgYm94cGxvdDsgdGhlIHZhbHVlcyBmb3IgdGhlIHpvbmUgY29tbXVuaXRpZXMgc2hvd24gYXMgc29saWQgY2lyY2xlcy4gKmJvdHRvbSo6IHRoZSBpbmRleCB2YWx1ZSBpcyBzaG93biBmb3IgZWFjaCBjb3VudHJ5LCBsb2xsaXBvcHMgYXJlIGNvbG9yZWQgYnkgdGhlIGxhdGl0dWRlIHpvbmUgdGhlIGNvdW50cnkgd2FzIGFzc2lnbmVkIHRvLiAKICAKICAKCgoKIyMjIFJhcmVmYWN0aW9uICYgU3BlY2llcyBBYnVuZGFuY2UgQ3VydmVzCgpSYXJlZmFjdGlvbiB3ZXJlIGNvbXB1dGVkIHVzaW5nIHRoZSB2ZWdhbjo6cmFyZWN1cnZlIGZ1bmN0aW9uIGZvciBzcGVjaW1lbnMgZ3JvdXBlZCBieSBlYWNoIG9mIGNvdW50cnkgYW5kIGxhdGl0dWRlIHpvbmUuCgoKYGBge3IgcmFyZWZhY3Rpb24uY29tcHV0YXRpb24sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNhY2hlPVRSVUV9CiMgIyBmdWxsIGRhdGEgcmFyZWZhY3Rpb24KIyBBcmFuZWFlLnJhciA8LSByYXJlY3VydmUoQXJhbmVhZS5kZi5iaW5zLCkKIyBBcmFuZWFlLnJhciA8LSB0aWJibGUoeSA9IEFyYW5lYWUucmFyW1sxXV0pICU+JQojICAgbXV0YXRlKHg9cm93X251bWJlcigpKQojIHdyaXRlX3JkcyhBcmFuZWFlLnJhciwgIi4vZGF0YS9BcmFuZWFlLnJhcmVmYWN0aW9uLnJkcyIpCiMgCiMgIyMgcmFyZWZhY3Rpb24gY3VydmVzIGJ5IGxhdCB6b25lCiMgQXJhbmVhZS56b25lLnJhciA8LSByYXJlY3VydmUoQXJhbmVhZS56b25lLmJpbnMpCiMgCiMgIyBtYW5pcHVsYXRlIGxpc3Qgb3V0cHV0IGZyb20gdmVnYW4gYmFjayBpbnRvIHRpZHkgZGF0YQojIEFyYW5lYWUuem9uZS5yYXIgPC0gdGliYmxlKHpvbmUgPSByb3duYW1lcyhBcmFuZWFlLnpvbmUuYmlucyksCiMgICAgICAgIGxpc3QgPSBBcmFuZWFlLnpvbmUucmFyKSAlPiUKIyAgICMgc3ByZWFkIGxpc3QgaW50byBpbmRpdmlkdWFsIGNvbHVtbnMKIyAgIHVubmVzdF93aWRlcihjb2wgPSBsaXN0KSAlPiUKIyAgICMgZ2V0IGxvbmcgZm9ybSB0YWJsZQojICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtem9uZSkgJT4lCiMgICAjIHJlbW92ZSByb3dzIG1pc3NpbmcgdmFsdWUgJiB1c2VsZXNzIG5hbWVzIGNvbHVtbgojICAgZmlsdGVyKCFpcy5uYSh2YWx1ZSkpICU+JQojICAgc2VsZWN0KC1uYW1lKSAlPiUKIyAgICMgY3JlYXRlIHZlY3RvciBmb3Igc2FtcGxpbmcgZGVwdGgKIyAgIGdyb3VwX2J5KHpvbmUpICU+JQojICAgbXV0YXRlKHNhbXBsZV9zaXplID0gcm93X251bWJlcigpKQojIHdyaXRlX3JkcyhBcmFuZWFlLnpvbmUucmFyLCAiLi9kYXRhL0FyYW5lYWUuem9uZXMucmFyZWZhY3Rpb24ucmRzIikKIyAKIyAjIyByYXJlZmFjdGlvbiBjdXJ2ZXMgYnkgY291bnRyeQojIEFyYW5lYWUuY291bnRyeS5yYXIgPC0gcmFyZWN1cnZlKEFyYW5lYWUuY291bnRyeS5iaW5zKQojIAojICMgbWFuaXB1bGF0ZSBsaXN0IG91dHB1dCBmcm9tIHZlZ2FuIGJhY2sgaW50byB0aWR5IGRhdGEKIyBBcmFuZWFlLmNvdW50cnkucmFyIDwtIHRpYmJsZShDb3VudHJ5ID0gcm93bmFtZXMoQXJhbmVhZS5jb3VudHJ5LmJpbnMpLAojICAgICAgICBsaXN0ID0gQXJhbmVhZS5jb3VudHJ5LnJhcikgJT4lCiMgICB1bm5lc3Rfd2lkZXIoY29sID0gbGlzdCkgJT4lCiMgICBwaXZvdF9sb25nZXIoY29scyA9IC1Db3VudHJ5KSAlPiUKIyAgIGZpbHRlcighaXMubmEodmFsdWUpKSAlPiUKIyAgIHNlbGVjdCgtbmFtZSkgJT4lCiMgICBncm91cF9ieShDb3VudHJ5KSAlPiUKIyAgIG11dGF0ZShzYW1wbGVfc2l6ZSA9IHJvd19udW1iZXIoKSkKIyB3cml0ZV9yZHMoQXJhbmVhZS5jb3VudHJ5LnJhciwgIi4vZGF0YS9BcmFuZWFlLmNvdW50cnkucmFyZWZhY3Rpb24ucmRzIikKYGBgCgoKU3BlY2llcyBhY2N1bXVsYXRpb24gY3VydmVzIHdlcmUgY29tcHV0ZWQgdXNpbmcgdGhlIHZlZ2FuOjpzcGVjYWNjdW0gZnVuY3Rpb24gZm9yIHNwZWNpbWVucyBncm91cGVkIGJ5IGVhY2ggb2YgY291bnRyeSBhbmQgbGF0aXR1ZGUgem9uZS4KCmBgYHtyIHNwZWNhY2N1bS5jb21wdXRhdGlvbiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2FjaGU9VFJVRX0KIyAjIyBTcGVjaWVzIGFjY3VtdWxhdGlvbiBjdXJ2ZXMKIyAjIHNwZWNhY2N1bSBieSBjb3VudHJ5CiMgU3BlY2FjY3VtLmNvdW50cnkgPC0gc3BlY2FjY3VtKEFyYW5lYWUuY291bnRyeS5iaW5zKQojIFNwZWNhY2N1bS5jb3VudHJ5IDwtIHRpYmJsZSgKIyAgIHNpdGVzID0gU3BlY2FjY3VtLmNvdW50cnlbJ3NpdGVzJ10sCiMgICByaWNobmVzcyA9IFNwZWNhY2N1bS5jb3VudHJ5WydyaWNobmVzcyddLAojICAgc2QgPSBTcGVjYWNjdW0uY291bnRyeVsnc2QnXSwKIyAgICkgJT4lCiMgICB1bm5lc3QoY29scyA9IGMoc2l0ZXMsIHJpY2huZXNzLCBzZCkpICU+JQojICAgbXV0YXRlKHNkMSA9IGlmZWxzZShyaWNobmVzcy1zZD49MCwgcmljaG5lc3Mtc2QsIDApLAojICAgICAgICAgIHNkMiA9IHJpY2huZXNzK3NkKQojIHdyaXRlX3JkcyhTcGVjYWNjdW0uY291bnRyeSwgIlNwZWNhY2N1bS5jb3VudHJ5LnJkcyIpCiMgCiMgIyBzcGVjYWNjdW0gYnkgem9uZQojIFNwZWNhY2N1bS56b25lIDwtIHNwZWNhY2N1bShBcmFuZWFlLnpvbmUuYmlucykKIyBTcGVjYWNjdW0uem9uZSA8LSB0aWJibGUoCiMgICBzaXRlcyA9IFNwZWNhY2N1bS56b25lWydzaXRlcyddLAojICAgcmljaG5lc3MgPSBTcGVjYWNjdW0uem9uZVsncmljaG5lc3MnXSwKIyAgIHNkID0gU3BlY2FjY3VtLnpvbmVbJ3NkJ10sCiMgICApICU+JQojICAgdW5uZXN0KGNvbHMgPSBjKHNpdGVzLCByaWNobmVzcywgc2QpKSAlPiUKIyAgIG11dGF0ZShzZDEgPSBpZmVsc2UocmljaG5lc3Mtc2Q+PTAsIHJpY2huZXNzLXNkLCAwKSwKIyAgICAgICAgICBzZDIgPSByaWNobmVzcytzZCkKIyB3cml0ZV9yZHMoU3BlY2FjY3VtLnpvbmUsICIuL2RhdGEvU3BlY2FjY3VtLnpvbmUucmRzIikKCmBgYAoKUGxvdHMgd2VyZSBjcmVhdGVkIGZvciB0aGUgcmFyZWZhY3Rpb24gYW5kIHNwZWNpZXMgYWNjdW11bGF0aW9uIGN1cnZlcyBpbiB0aGUgZm9sbG93aW5nIGNvZGU6CgpgYGB7ciBlY29sLmFuYWx5c2lzLCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjYWNoZT1UUlVFfQojIyBSQVJFRkFDVElPTgojIHJlYWQgaW4gcmFyLiBjdXJ2ZSBkYXRhIGNvbXB1dGVkIGFib3ZlCkFyYW5lYWUucmFyIDwtIHJlYWRfcmRzKCIuL2RhdGEvQXJhbmVhZS5yYXJlZmFjdGlvbi5yZHMiKQpBcmFuZWFlLnpvbmUucmFyIDwtIHJlYWRfcmRzKCIuL2RhdGEvQXJhbmVhZS56b25lcy5yYXJlZmFjdGlvbi5yZHMiKQpBcmFuZWFlLmNvdW50cnkucmFyIDwtIHJlYWRfcmRzKCIuL2RhdGEvQXJhbmVhZS5jb3VudHJ5LnJhcmVmYWN0aW9uLnJkcyIpCgojIHJhcmVmYWN0aW9uIHBsb3QgZm9yIGVudGlyZSBkYXRhc2V0CnBsb3QucmFyLmZ1bGwgPC0gQXJhbmVhZS5yYXIgJT4lCiAgZ2dwbG90KGFlcyh4PXgvMTAwMCwgeT15KSkgKwogIGdlb21fbGluZSgpICsKICBsYWJzKHkgPSAnVW5pcXVlIEJJTnMnLCB4ID0gJ1NhbXBsZSBzaXplIChrKScpICsKICB0aGVtZV9jbGFzc2ljKCkKCiMgcmFyZWZhY3Rpb24gY3VydmVzIGZvciBsYXRpdHVkZSB6b25lcwpwbG90LnJhci56b25lIDwtIGdncGxvdChBcmFuZWFlLnpvbmUucmFyLAogICAgICAgICAgICAgICAgICAgICAgICBhZXMoeD1zYW1wbGVfc2l6ZS8xMDAwLCB5ID0gdmFsdWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IHpvbmUsIGNvbG91ciA9IHpvbmUpKSArCiAgZ2VvbV9saW5lKGFscGhhID0gMC43KSArCiAgc2NhbGVfY29sb3VyX2Rpc2NyZXRlKCdMYXQuIHpvbmUnKSArCiAgbGFicyh4ID0gJ1NhbXBsZSBzaXplIChrKScsIHkgPSAnVW5pcXVlIEJJTnMnKSArCiAgdGhlbWVfY2xhc3NpYygpCgojIGFkZGVkIGxhdCB6b25lIGxhYmVscyB0byBjb3VudHJ5IHJhcmVmYWN0aW9uIGN1cnZlcyBkYXRhIGZvciBwbG90CkFyYW5lYWUuY291bnRyeS5yYXIgPC0gbGVmdF9qb2luKEFyYW5lYWUuY291bnRyeS5yYXIsIGNvdW50cnlfem9uZXMsIGJ5ID0gJ0NvdW50cnknKQoKIyBwbG90IHJhcmVmYWN0aW9uIGN1cnZlcyBmb3IgZWFjaCBjb3VudHJ5LCBjb2xvdXIgYnkgem9uZQpwbG90LnJhci5jb3VudHJ5IDwtCiAgQXJhbmVhZS5jb3VudHJ5LnJhciAlPiUKICBmaWx0ZXIoIWlzLm5hKHpvbmUpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9c2FtcGxlX3NpemUvMTAwMCwgeSA9IHZhbHVlKSkgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBDb3VudHJ5LCBjb2xvdXIgPSB6b25lKSwgYWxwaGEgPSAwLjcpICsKICAjIGFkZCBsYWJlbHMgZm9yIDEwIG1vc3Qtc2FtcGxlZCBjb3VudHJpZXMKICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGNvdW50cnkuc3BlY2ltZW5zLnRhYmxlWzE6MTAsXSwKICAgICAgICAgICAgICAgICAgIGFlcyhsYWJlbCA9IGNvdW50cnksIHggPSBzcGVjaW1lbnMvMTAwMCwgeSA9IHNwZWNpZXMpLAogICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDAsIHNpemUgPSAzLAogICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSArCiAgc2NhbGVfY29sb3VyX2Rpc2NyZXRlKCdMYXQuIHpvbmUnKSArCiAgbGFicyh4ID0gJ1NhbXBsZSBzaXplIChrKScsIHkgPSAnVW5pcXVlIEJJTnMnKSArCiAgdGhlbWVfY2xhc3NpYygpCgpwbG90LnJhci5jb3VudHJ5MiA8LSAKICBBcmFuZWFlLmNvdW50cnkucmFyICU+JQogIGZpbHRlcighaXMubmEoem9uZSkpICU+JQogIGdncGxvdChhZXMoeD1zYW1wbGVfc2l6ZSwgeSA9IHZhbHVlKSkgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBDb3VudHJ5LCBjb2xvdXIgPSB6b25lKSwgYWxwaGEgPSAwLjcpICsKICAjIGFkZCBsYWJlbHMgZm9yIDEwIG1vc3Qtc2FtcGxlZCBjb3VudHJpZXMKICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGNvdW50cnkuc3BlY2ltZW5zLnRhYmxlWzE6MTAsXSwKICAgICAgICAgICAgICAgICAgIGFlcyhsYWJlbCA9IGNvdW50cnksIHggPSBzcGVjaW1lbnMsIHkgPSBzcGVjaWVzKSwKICAgICAgICAgICAgICAgICAgIG51ZGdlX3ggPSAwLCBzaXplID0gMywKICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkgKwogIHNjYWxlX2NvbG91cl9kaXNjcmV0ZSgnTGF0LiB6b25lJykgKwogIGxhYnMoeCA9ICdTYW1wbGUgc2l6ZScsIHkgPSAnVW5pcXVlIEJJTnMnKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB4bGltKGMoMCwgNTAwKSkgKwogIHlsaW0oYygwLCAzNDApKQoKCiMjIFNQRUNJRVMgQUNDVU1VTEFUSU9OClNwZWNhY2N1bS5jb3VudHJ5IDwtIHJlYWRfcmRzKCIuL2RhdGEvU3BlY2FjY3VtLmNvdW50cnkucmRzIikKU3BlY2FjY3VtLnpvbmUgPC0gcmVhZF9yZHMoIi4vZGF0YS9TcGVjYWNjdW0uem9uZS5yZHMiKQoKIyBwbG90IHNwZWNpZXMgYWNjdW11bGF0aW9uIGJ5IGNvdW50cnkKcGxvdC5TcGVjYWNjdW0uY291bnRyeSA8LSAgZ2dwbG90KFNwZWNhY2N1bS5jb3VudHJ5KSArCiAgZ2VvbV9yaWJib24oYWVzKHg9c2l0ZXMsIHk9cmljaG5lc3MsIHltaW4gPSBzZDEsIHltYXggPSBzZDIpLAogICAgICAgICAgICAgIGZpbGwgPSAnY29ybmZsb3dlcmJsdWUnLCBhbHBoYSA9IDAuMykgKwogIGdlb21fbGluZShhZXMoeCA9IHNpdGVzLCB5ID0gcmljaG5lc3MpLAogICAgICAgICAgICBzaXplID0gMS4zLCBjb2xvdXIgPSAnYmx1ZTQnLCBhbHBoYSA9IDAuNykgKwogIGxhYnMoeSA9ICdCSU4gUmljaG5lc3MnLCB4ID0gJ0NvdW50cmllcycpICsKICB0aGVtZV9jbGFzc2ljKCkKCiMgcGxvdCBzcGVjaWVzIGFjY3VtdWxhdGlvbiBieSBsYXRpdHVkZSB6b25lCnBsb3QuU3BlY2FjY3VtLnpvbmUgPC0gIGdncGxvdChTcGVjYWNjdW0uem9uZSkgKwogIGdlb21fcmliYm9uKGFlcyh4PXNpdGVzLCB5PXJpY2huZXNzLCB5bWluID0gc2QxLCB5bWF4ID0gc2QyKSwKICAgICAgICAgICAgICBmaWxsID0gJ3JlZCcsIGFscGhhID0gMC4yKSArCiAgZ2VvbV9saW5lKGFlcyh4ID0gc2l0ZXMsIHkgPSByaWNobmVzcyksCiAgICAgICAgICAgIHNpemUgPSAxLjMsIGNvbG91ciA9ICdyZWQzJywgYWxwaGEgPSAwLjcpICsKICBsYWJzKHkgPSAnQklOIFJpY2huZXNzJywgeCA9ICdMYXRpdHVkZSB6b25lcycpICsKICB0aGVtZV9jbGFzc2ljKCkKCiMjIGNyZWF0ZSByYXJlZmFjdGlvbi9zcGVjYWNjdW0gcGxvdHMgZmlndXJlCgpgYGAKCiAgIApgYGB7ciBzaG93LnJhcmVmYWN0aW9uLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjYWNoZT1UUlVFfQojIHNob3cgcmFyZWZhY3Rpb24gcGxvdHMgcGFuZWwgd2l0aCBwYXRjaHdvcms6OgoocGxvdC5yYXIuZnVsbCArIHBsb3QucmFyLnpvbmUpIC8gCiAgKHBsb3QucmFyLmNvdW50cnkgKyBwbG90LnJhci5jb3VudHJ5MikgLwogIChwbG90LlNwZWNhY2N1bS5jb3VudHJ5ICsgcGxvdC5TcGVjYWNjdW0uem9uZSkgKwogIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gJ0EnKSArCiAgcGxvdF9sYXlvdXQoZ3VpZGVzID0gJ2NvbGxlY3QnKSAmIAogIHRoZW1lKHBsb3QudGFnLnBvc2l0aW9uID0gYygwLCAxKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLAogICAgICAgIHBsb3QudGFnID0gZWxlbWVudF90ZXh0KHNpemUgPSA4LCBoanVzdCA9IDAsIHZqdXN0ID0gMCkpCmBgYAogICAgCioqRmlndXJlIDMuIEEtRDoqKiBSYXJlZmFjdGlvbiBjdXJ2ZXMgZm9yIGVudGlyZSBjb2xsZWN0aW9uIG9mIEJPTEQgc3BpZGVyIHNwZWNpbWVucyAoQSksIGJ5IGxhdGl0dWRlIHpvbmUgKEIpLCBhbmQgYnkgc291cmNlIGNvdW50cnkgKEMpLiBCZWNhdXNlIG9mIHRoZSBkaXNjcmVwZW5jeSBpbiBzYW1wbGluZywgYSBjbG9zZS11cCBvZiB0aGUgY291bnRyaWVzJyByYXJlZmFjdGlvbiBjdXJ2ZXMgYXJlIHNob3duIGZvciBzbWFsbGVyIHNhbXBsZSBzaXplcyAoRCkuIEN1cnZlcyBhcmUgY29sb3VyZWQgYnkgbGF0aXR1ZGUgem9uZSB3aGVyZSBhcHBsaWNhYmxlLiBDb3VudHJpZXMgYXJlIGFzc2lnbmVkIHRvIGxhdGl0dWRlIHpvbmVzIGJ5IHRoZSBtZWFuIGxhdGl0dWRlIG9mIGFsbCB0aGVpciBzYW1wbGVzLiAgUmFyZWZhY3Rpb24gY3VydmVzIHdlcmUgY29tcHV0ZWQgdXNpbmcgdGhlIGB2ZWdhbjo6cmFyZWN1cnZlYCBmdW5jdGlvbi4gICoqRUY6KiogU3BlY2llcyBhY2N1bXVsYXRpb24gY3VydmVzIHdlcmUgY29tcHV0ZWQgdXNpbmcgdGhlIHZlZ2FuOjpzcGVjYWNjdW0gZnVuY3Rpb24gZm9yIHNwZWNpbWVucyBncm91cGVkIGJ5IGVhY2ggb2YgY291bnRyeSAoRSkgYW5kIGxhdGl0dWRlIHpvbmUgKEYpOyBsaW5lcyBzaG93IHJpY2huZXNzICsvLSBzZC4KCgojIyMgT3JkaW5hdGlvbiBieSBOTURTIGFuZCBzcGVjaWVzIG5ldHdvcmsgYW5heWxzaXMKCmBgYHtyIG5tZHMucGxvdCwgZmlnLmhlaWdodD00LCBmaWcuc2hvdz0naG9sZCcsIGZpZy53aWR0aD01LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjYWNoZT1UUlVFfQojIE5NRFMKem9uZS5ubWRzIDwtIG1ldGFNRFMoQXJhbmVhZS56b25lLmJpbnMsIGRpc3RhbmNlID0gJ2JyYXknLCB0cmFjZSA9IEZBTFNFKQojIHpvbmUubm1kcwpwYXIobWFyPWMoNSw0LDEsMSkpCnBsb3Qoem9uZS5ubWRzLCBhbHBoYT0wLjUsIGNleCA9IDAuNykKdGV4dCh6b25lLm5tZHMsIGRpc3BsYXkgPSAnc2l0ZXMnLCBjZXggPSAwLjkpCmBgYAogICAgCioqRmlndXJlIDUuKiogTk1EUyBvZiBzcGlkZXIgQklOIGFidW5kYW5jZXMgaW4gZm91ciBsYXRpdHVkZSB6b25lcyB1c2luZyBCcmF5IGRpc3RhbmNlIGFuZCBXaXNjb25zaW4gc3RhbmRhcmRpemF0aW9uIG9mIHNxdWFyZS1yb290LXRyYW5zZm9ybWVkIGFidW5kYW5jZXMuCgoKICAKYGBge3IgbmV0d29yaywgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD00LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjYWNoZT1UUlVFfQojIyBOZXR3b3JrIHBsb3Qgd2l0aCBzaGFyZWQgQklOcyBiZXR3ZWVuIHpvbmVzCkFyYW5lYWUuem9uZS5iaW5zIDwtIHJlYWRfcmRzKCIuL2RhdGEvQXJhbmVhZS56b25lLmJpbnMucmRzIikKIyBtYWtlIGFuIGVkZ2VsaXN0IGZvciBzaW1wbGUgZ3JhcGggKGZvciBiaW5zIHNoYXJlZCBiZXR3ZWVuIHpvbmVzKQplZGdlbGlzdCA8LSB0aWJibGUoCiAgdSA9IGMocm93bmFtZXMoQXJhbmVhZS56b25lLmJpbnMpKSwKICB2ID0gcmVwKGxpc3Qocm93bmFtZXMoQXJhbmVhZS56b25lLmJpbnMpKSw0KQopICU+JQogIHVubmVzdCh2KSAlPiUKICBmaWx0ZXIoIXU9PXYpCgoKIyBnZXQgcmlkIG9mIGR1cGxpY2F0ZSBlZGdlcyBpbiBlZGdlbGlzdCAoc2luY2UgZ3JhcGggaXMgbm90IGRpcmVjdGlvbmFsKQplZGdlLnN0cmluZ3MgPC0gIHN0cl9zcGxpdChwYXN0ZShlZGdlbGlzdCR1LCBlZGdlbGlzdCR2KSwgJyAnKQojIHNvcnQgZWRnZXMgdG8gcmVtb3ZlIGRpcmVjdGlvbmFsaXR5CmVkZ2VsaXN0IDwtIHVuaXF1ZShsYXBwbHkoZWRnZS5zdHJpbmdzLCBmdW5jdGlvbih4KSB1bmlxdWUoc29ydCh4KSkpKQojIHJlbW92ZSBzZWxmLXNlbGYgZWRnZXMKZWRnZWxpc3QgPC0gZWRnZWxpc3Rbd2hpY2gobGVuZ3RocyhlZGdlbGlzdCk+MSldCiMgcGFzdGUgdSB2IHZlcnRpY2VzIGZvciBlYWNoIGVkZ2UgdG8gZmlsdGVyIGJpbnMuZWRnZWxpc3QgbGF0ZXIgKGJlbG93KQplZGdlbGlzdCA8LSBsYXBwbHkoZWRnZWxpc3QsIGZ1bmN0aW9uKHgpIHBhc3RlMCh4LCBjb2xsYXBzZSA9ICcgJykpCnJtKGVkZ2Uuc3RyaW5ncykKCiMgR2V0IGxpc3Qgb2YgdW5pcXVlIGJpbnMgZm9yIGVhY2ggem9uZSBmcm9tIHpvbmUgYWJ1bmQuIG1hdHJpeAp6b25lLmJpbnMubGlzdCA8LSB0aWJibGUoQXJhbmVhZS56b25lLmJpbnMpICU+JQogIG11dGF0ZSh6b25lID0gcm93bmFtZXMoQXJhbmVhZS56b25lLmJpbnMpKSAlPiUKICBwaXZvdF9sb25nZXIoLXpvbmUpICU+JQogIGZpbHRlcighdmFsdWUgPT0gMCkgJT4lCiAgZ3JvdXBfYnkoem9uZSkgJT4lCiAgbXV0YXRlKGJpbnMgPSBsaXN0KG5hbWUpKSAlPiUKICBzZWxlY3QoLWModmFsdWUsIG5hbWUpKSAlPiUKICBkaXN0aW5jdCgpICU+JQogIG11dGF0ZSh1bmlxdWVzID0gdW5pcXVlKGJpbnMpKSAKCgojIENyZWF0ZSBtYXRyaXggd2l0aCBzaXplcyBvZiBpbnRlcnNlY3Qgb2YgdW5pcXVlIGJpbnMgYmV0d2VlbiB6b25lcy4gRWFjaCBjb2wgaGFzIHRoZSBzaXplIG9mIHRoZSBpbnRlcnNlY3Rpb24gYmV0d2VlbiBhIHpvbmUgYW5kIGVhY2ggem9uZSAoc2VsZi1zZWxmIGlzIG9uIGRpYWdvbmFsKSAtIGZvciBuZXR3b3JrIGVkZ2Ugd2VpZ2h0cwpiaW5zLmxzIDwtIHpvbmUuYmlucy5saXN0ICU+JQogIHNlbGVjdCh6b25lLCBiaW5zKSAlPiUKICBtdXRhdGUoRXh0cmVtZSA9IGxlbmd0aChpbnRlcnNlY3Qoem9uZS5iaW5zLmxpc3RbMSwgM11bWzFdXVtbMV1dLCBiaW5zW1sxXV0pKSwKICAgICAgICAgVGVtcGVyYXRlID0gbGVuZ3RoKGludGVyc2VjdCh6b25lLmJpbnMubGlzdFsyLCAzXVtbMV1dW1sxXV0sIGJpbnNbWzFdXSkpLAogICAgICAgICBgU3ViLXRyb3BpY2FsYCA9IGxlbmd0aChpbnRlcnNlY3Qoem9uZS5iaW5zLmxpc3RbMywgM11bWzFdXVtbMV1dLCBiaW5zW1sxXV0pKSwKICAgICAgICAgVHJvcGljYWwgPSBsZW5ndGgoaW50ZXJzZWN0KHpvbmUuYmlucy5saXN0WzQsIDNdW1sxXV1bWzFdXSwgYmluc1tbMV1dKSksCiAgKSAlPiUKICBzZWxlY3QoLWJpbnMpICU+JQogIHBpdm90X2xvbmdlcihFeHRyZW1lOlRyb3BpY2FsKSAlPiUKICByZW5hbWUoem9uZTEgPSB6b25lLAogICAgICAgICB6b25lMiA9IG5hbWUsCiAgICAgICAgIHdlaWdodCA9IHZhbHVlKQoKIyBGaWx0ZXIgd2VpZ2h0ZWQgZWRnZWxpc3QgdG8ga2VlcCBzaW5nbGUgZWRnZSBmb3IgZWFjaCBwYWlyIChub3QgYmlkaXJlY3Rpb25hbCAtIG1hZGUgJ2VkZ2VsaXN0JyBhdCB0b3Agb2YgY2h1bmspCmJpbnMuZWRnZXMgPC0gYmlucy5scyAlPiUKICBmaWx0ZXIoIXpvbmUxID09IHpvbmUyKSAlPiUKICBtdXRhdGUoZWRnZSA9IHBhc3RlKHpvbmUxLCB6b25lMikpICU+JQogIGZpbHRlcihlZGdlICVpbiUgZWRnZWxpc3QpICU+JQogIHNlbGVjdCgtZWRnZSkKCgojIHRvdGFsIG51bWJlciBvZiB1bmlxdWUgYmlucyBhdCBlYWNoIHpvbmUgLSBmb3IgdmVydGV4IHNpemUKdG90YWxfYmlucyA8LSBiaW5zLmxzICAlPiUKICBmaWx0ZXIoem9uZTEgPT0gem9uZTIpICU+JQogIHNlbGVjdCgtem9uZTIpICU+JQogIHJlbmFtZShzaXplID0gd2VpZ2h0KQoKbmV0IDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkPSBiaW5zLmVkZ2VzLCB2ZXJ0aWNlcyA9IHRvdGFsX2JpbnMsIGRpcmVjdGVkID0gRikKCiN2ZXJ0aWNlIHByb3BlcnRpZXMKVihuZXQpJGNvbG9yIDwtIGMoICdjeWFuJywgImdvbGQiLCAidG9tYXRvIiwgInBsdW0iKQpWKG5ldCkkc2l6ZSA8LSB0b3RhbF9iaW5zJHNpemUvMTAwICsgMjAKCiMgZWRnZSBwcm9wZXJ0aWVzCkUobmV0KSR3ZWlnaHQgPC0gYmlucy5lZGdlcyR3ZWlnaHQqMTAwCkUobmV0KSR3aWR0aCA8LSBzcXJ0KEUobmV0KSR3ZWlnaHQpLzIwCkUobmV0KSRlZGdlLmxhYmVsIDwtIGJpbnMuZWRnZXMkd2VpZ2h0CkUobmV0KSRlZGdlLmNvbG9yIDwtICJncmF5OTAiCkUobmV0KSRhcnJvdy5zaXplIDwtIC4wCgojIFBsb3Qgc3BlY2llcyBuZXR3b3JrCnNldC5zZWVkKDQpCnBhcihtYXI9YygxLDEsMSwxKSkKcGxvdChuZXQsIAogICAgIGxheW91dCA9IGxheW91dC5mcnVjaHRlcm1hbi5yZWluZ29sZChuZXQpLAogICAgIGxhYmVsLmRpc3QgPSAyLAogICAgIGVkZ2UubGFiZWwgPSBiaW5zLmVkZ2VzJHdlaWdodCwKICAgICBlZGdlLmxhYmVsLmNvbG9yID0ibmF2eSIsCiAgICAgZWRnZS5sYWJlbC5jZXggPSAwLjgsCiAgICAgZWRnZS5sYWJlbC5mYW1pbHkgPSAnc2FucycsCiAgICAgdmVydGV4LmxhYmVsID0gcGFzdGUwKFYobmV0KSRuYW1lLCAnXG4oJywgdG90YWxfYmlucyRzaXplLCAnKScpLAogICAgIHZlcnRleC5sYWJlbC5jb2xvcj0iYmxhY2siLAogICAgIHZlcnRleC5sYWJlbC5mYW1pbHkgPSAnc2FucycsCiAgICAgdmVydGV4LmxhYmVsLmZvbnQgPSAyLAogICAgIHZlcnRleC5sYWJlbC5jZXg9LjcsCiAgICAgdmVydGV4LmZyYW1lLmNvbG9yID0gJ3doaXRlJykKYGBgCiAgCiAgCioqRmlndXJlIDYuKiogTmV0d29yayBvZiBsYXRpdHVkZS16b25lZCBzcGlkZXIgYXNzZW1ibGFnZXMgbGlua2VkIGJ5IHNoYXJlZCBiYXJjb2RlcyBzaG93cyB0aGF0IHNpbWlsYXJpdHkgaW5jcmVhc2VzIHdpdGggbGF0aXR1ZGUuIFZlcnRpY2VzIHJlcHJlc2VudCBsYXRpdHVkZSB6b25lIGFuZCBCSU4gcmljaG5lc3M7IGVkZ2VzIGFyZSB3aWVnaHRlZCBieSB0aGUgbnVtYmVyIG9mIHNoYXJlZCBCSU5zIGJldHdlZW4gem9uZXMuCiAgIAoKLS0tLQoKCiMgRGlzY3Vzc2lvbgoKPCEtLSAjIHN1bW1hcml6ZSAtLT4KCkluIHRoaXMgd29yayBJIGV4YW1pbmVkIHRoZSBsYXRpdHVkaW5hbCBkaXZlcnNpdHkgZ3JhZGllbnQgaW4gRE5BLWJhcmNvZGVkIHNwaWRlciBzcGVjaW1lbnMgcmVjb3JkZWQgaW4gQk9MRDsgYXMgd2VsbCBhcyB0byBldmFsdWF0ZSBnZW9ncmFwaGljYWwgc2FtcGxpbmcgYmlhcyBpbiB0aGlzIGNvbGxlY3Rpb24uIFRvIHRoaXMgZW5kLCBhIG51bWJlciBvZiBlY29sb2dpY2FsIGFuYWx5c2lzIHdlcmUgcGVyZm9ybWVkIGluY2x1ZGluZyByYXJlZmFjdGlvbiwgc3BlY2llcyBhY2N1bXVsYXRpb24sIGFuZCBvcmRpbmF0aW9uLiBUaGUgQmFyY29kZSBvZiBMaWZlIGRhdGFiYXNlIChCT0xEKSBjb250YWlucyBhIGh1Z2UgbnVtYmVyIG9mIHNwaWRlciBzcGVjaW1lbiByZWNvcmRzICgxMjRrKSBhbmQgYXNzb2NpYXRlZCBETkEtYmFyY29kZSBzZXF1ZW5jZXMgKDEwNms7IHRhYmxlIDEpIFtAUmF0bmFzaW5naGFtMjAwNzsgQFJhdG5hc2luZ2hhbTIwMTNdLiBUaGVyZSBpcyBhIHN1cnByaXNpbmdseSBsYXJnZSBudW1iZXIgb2YgdW5pcXVlIEROQSBiYXJjb2RlIGluZGVudGlmaWVycyAoQklOcykgY29tcGFyZWQgdG8gc3BlY2llcyBuYW1lcyAoOSw4NDUgKnZzKiAzLDgyMikuIEFkZGl0aW9uYWxseSBsYXJnZSBudW1iZXIgb2Ygc3BlY2ltZW5zIGFyZSBtaXNzaW5nIHRheG9ub21pYyBsYWJlbHMgYXQgdGhlIGZhbWlseSwgZ2VudXMsIGFuZCBzcGVjaWVzIGxldmVscyAoMTdrLCAyMWssIGFuZCAyM2sgcmVjb3JkcywgcmVzcGVjdGl2ZWx5KSwgaW5kaWNhdGluZyB0aGF0IGJhcmNvZGUtYmFzZWQgYW5hbHlzaXMgaXMgZXNwZWNpYWxseSB1c2VmdWwgZm9yIHNwaWRlcnMuIE1vc3QgYmFyY29kZXMgaGF2ZSBvbmx5IGEgZmV3IHNwZWNpbWVucywgYW5kIHRoZSBudW1iZXIgb2Ygc3BlY2ltZW5zIHBlciBiYXJjb2RlIHNlcXVlbmNlIGhhcyBhIG5lZ2F0aXZlIGJpbm9taWFsIGRpc3RyaWJ1dGlvbiAoZmlnLiAyIHJpZ2h0KQoKPCEtLSBnbG9iYWwgc2FtcGxpbmcgZWZmb3J0IC0tPgpUbyBldmFsdWF0ZSB0aGUgZ2xvYmFsIGRpc3RyaWJ1dGlvbiBvZiB0aGUgc2FtcGxpbmcgZWZmb3J0IHJlcHJlc2VudGVkIGluIHRoZSBCT0xEIHNwaWRlciBjb2xsZWN0aW9uLCBhbGwgcmVjb3JkcyBoYXZpbmcgYmFyY29kZXMgYW5kIGdlb2RhdGEgKDk2aykgd2VyZSBiaW5uZWQgaW50byBhIDEgZGVnIGdyaWQgYW5kIG1hcHBlZCAoZmlnLiAxKS4gU3Ryb25nIE5vcnRoIEFtZXJpY2FuIGFuZCBFdXJvcGVhbiBzYW1wbGluZyBiaWFzIGlzIGV2aWRlbnQ7IHZhc3Qgc3dhdGhzIG9mIEFmcmljYSBhbmQgQ2VudHJhbCBBc2lhIGhhdmUgbm8gcmVwcmVzZW50YXRpdmVzLiBUaGUgc2FtcGxpbmcgb2Ygc3BpZGVyIHNwZWNpbWVucyBpcyBoZWF2aWx5IHNrZXdlZCB0byBub3J0aGVybiBsYXRpdHVkZXMgKGZpZy4gMiBsZWZ0KSB0aG91Z2ggdGhpcyBpcyByb3VnaGx5IHByb3BvcnRpb25hbCB0byBvdmVyYWxsIGxhbmRtYXNzLiBXaGlsZSB0aGVyZSBhcmUgYSBsYXJnZSBudW1iZXIgb2Ygc3BpZGVyIGZhbWlsaWVzIHJlcHJlc2VudGVkIGluIHRoZSBkYXRhc2V0LCBhIGZldyBmYW1pbGllcyAoKkxpbnlwaGlpZGFlKiwgKkx5Y29zaWRhZSogYW5kICpBcmFuZWlkYWUqKSB0ZW5kIHRvIGRvbWluYXRlIGNvbW11bml0aWVzIGFjcm9zcyBsYXRpdHVkZXMuCgo8IS0tIGxhdGl0dWRpbmFsIGRpdmVyc2l0eSAtLT4KU3BpZGVycyBiaW9kaXZlcnNpdHkgaXMgZ2VuZXJhbGx5IGtub3duIHRvIGRlY3JlYXNlIHdpdGggZGlzdGFuY2UgZnJvbSB0aGUgZXF1YXRvciBbQFBsYXRuaWNrMTk5MTsgQFBpZWwyMDE4XS4gVG8gZXZhbHVhdGUgdGhlIGxhdGl0dWRpbmFsIGRpdmVyc2l0eSBncmFkaWVudCBvZiB0aGUgQk9MRCBzcGlkZXJzIGRhdGEsIEkgZmlyc3QgZ3JvdXBlZCByZWNvcmRzIGludG8gZm91ciAnbGF0aXR1ZGluYWwgY29tbXVuaXRpZXMnIGJhc2VkIG9uIGFic29sdXRlIGxhdGl0dWRlOiB0cm9waWNhbCAoKy8tMC0yMCBkZWcpLCBzdWItdHJvcGljYWwgKDIwLTQwKSwgdGVtcGVyYXRlICg0MC02MCkgYW5kIGV4dHJlbWUgKDYwKykuIFNpbWlsYXJseSwgc3BlY2ltZW4tc291cmNlIGNvdW50cmllcyB3ZXJlIGNhdGVnb3JpemVkIGludG8gdGhlc2Ugem9uZXMgYmFzZWQgb24gdGhlIG1lYW4gbGF0aXR1ZGUgb2Ygc3BlY2ltZW5zIGNvbGxlY3RlZCBpbiBlYWNoIGNvdW50cnkuIAoKPCEtLSByYXJlZmFjdGlvbiAtLT4KRGl2ZXJzaXR5IGFuYWx5c2VzIG9mIHRoZXNlIG5hdGlvbmFsIGFuZCBsYXRpdHVkaW5hbCBjb21tdW5pdGllcyBzaG93ZWQgdGhhdCBkaXZlcnNpdHkgZ2VuZXJhbGx5IGRlY3JlYXNlcyB3aXRoIGRpc3RhbmNlIGZyb20gdGhlIGVxdWF0b3IsIGFzIHdhcyBleHBlY3RlZCBmcm9tIHByZXZpb3VzIHJlc2VhcmNoIFtAUGxhdG5pY2sxOTkxOyBAUGllbDIwMThdLiBPdmVyYWxsLCB0aGUgc3ViLXRyb3BpY2FsIHpvbmUgY29udGFpbmVkIHRoZSBncmVhdGVzdCBiYXJjb2RlIChCSU4pIHJpY2huZXNzIGZvbGxvd2VkIGJ5IHRoZSB0ZW1wZXJhdGUgYW5kIHRyb3BpY2FsIHpvbmVzICh0YWJsZSAyLCBmaWcgMmIuKS4gUmFyZWZhY3Rpb24gYW5hbHlzaXMgc2hvd2VkIHRoYXQgdGhlIHN1Yi10cm9waWNhbCBhbmQgdHJvcGljYWwgY29tbXVuaXRpZXMgYXJlIGZhaXJseSBzaW1pbGFyIGluIHRlcm1zIG9mIGRpdmVyc2l0eSBhbmQgYXJlIG1vcmUgZGl2ZXJzZSB0aGFuIHRoZSB0ZW1wZXJhdGUgYW5kIGV4dHJlbWUgbGF0aXR1ZGUgem9uZXMgKGZpZy4gM2IpLiBXaGVuIG5hdGlvbmFsIGNvbW11bml0aWVzIGFyZSBjb25zaWRlcmVkLCB3ZSBjYW4gc2VlIHRoYXQgdGhlcmUgaXMgYSBsYXJnZSBkZWdyZWUgb2YgdmFyaWFuY2UgaW4gZGl2ZXJzaXR5IGJldHdlZW4gY291bnRyaWVzIGF0IHNpbWlsYXIgZGlzdGFuY2VzIGZyb20gdGhlIGVxdWF0b3IsIGFuZCB0aGlzIGlzIGVzcGVjaWFsbHkgdHJ1ZSBmb3IgdGhlIGNvbW11bml0aWVzIG9mIHRoZSBmZXcgdHJvcGljYWwgbmF0aW9ucyBleGFtaW5lZCAob25seSBmaWcuIDNjLGQpLgoKPCEtLSBhbHBoYSBkaXZlcnNpdHkgLS0+CldoZW4gY29uc2lkZXJpbmcgZXF1YWwgc2FtcGxlIHNpemVzLCB0aGUgc3ViLXRyb3BpY2FsIHpvbmUgaGFkIHRoZSBncmVhdGVzdCByYXJlZmllZCBCSU4gcmljaG5lc3MgYnV0IHRoaXMgd2FzIG9ubHkgc2xpZ2h0bHkgbGFyZ2VyIHRoYW4gdGhlIHRyb3BpY2FsIHpvbmUgKHRhYmxlIDIsIGZpZy4gNCkuIFRlbXBlcmF0ZSBhbmQgZXh0cmVtZSBsYXRpdHVkZXMgaGFkIHJlbGF0aXZlbHkgbG93IFNoYW5ub24gZGl2ZXJzaXR5LCB3aGlsZSB0aGUgc3VidHJvcGljYWwtem9uZSBoYWQgYSBzbGlnaHRseSBncmVhdGVyIFNoYW5ub24gZGl2ZXJzaXR5IHRoYW4gdGhlIHRyb3BpY2FsIHpvbmUuIFNpbXBzb24gZGl2ZXJzaXR5IHdhcyBub3QgdmVyeSBpbmZvcm1hdGl2ZSBmb3IgZGlmZmVyZW50aWF0aW5nIGNvbW11bml0aWVzIGF0IHRoZSB6b25lIG9yIGNvdW50cnkgbGV2ZWwsIHdpdGggbW9zdCB2YWx1ZXMgYXBwcm9hY2hpbmcgMS4gQW5vdmEgdGVzdHMgb2YgY291bnRyaWVzJyByaWNobmVzcyBhbmQgU2hhbm5vbiBpbmRleCBkYXRhIHNob3dlZCB0aGF0IHRoZSBkaWZmZXJlbmNlcyBpbiBtZWFucyBiZXR3ZWVuIGxhdGl0dWRlIHpvbmVzIHdlcmUgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuIFRoaXMgYW5hbHlzaXMgd2FzIGhpbmRlcmVkIGJ5IHRoZSBsb3cgbnVtYmVyIG9mIHNpdGUgY291bnRyaWVzIGhhdmluZyBlbm91Z2ggc3BlY2ltZW5zIChuPjQ5OSwgY291bnRyaWVzPTIxKSBhbmQgdGhlc2Ugd2VyZSBjb25jZW50cmF0ZWQgaW4gdGhlIHRlbXBlcmF0ZSBhbmQgc3VidHJvcGljYWwgem9uZXMsIGxlYWRpbmcgdG8gbGFyZ2UgZXJyb3IgdmFsdWVzIGluIGVzdGltYXRpbmcgdGhlIGRpdmVyc2l0eSBvZiB0cm9waWNhbCBhbmQgZXh0cmVtZSB6b25lcy4gT3ZlcmFsbCwgdGhlIEJPTEQgc3BpZGVycyBkYXRhIGZvbGxvdyB0aGUgZXhwZWN0ZWQgbmVnYXRpdmUgbGF0aXR1ZGUtZGl2ZXJzaXR5IHRyZW5kOyBob3dldmVyLCBwZWFrIHJpY2huZXNzIGFuZCBkaXZlcnNpdHkgd2FzIG9ic2VydmVkIGluIHRoZSBzdWItdHJvcGljYWwgem9uZXMgKCsvLSAyMC00MCBkZWcgbGF0aXR1ZGUpLgoKCjwhLS0gTk1EUyArIE5FVFdPUksgLS0+Ck9yZGluYXRpb24gYW5kIG5ldHdvcmsgYW5hbHlzaXMgb2YgbGF0aXR1ZGUgem9uZSBjb21tdW5pdGllcyBzaG93ZWQgdGhhdCB0aGUgdGVtcGVyYXRlIGFuZCBleHRyZW1lIHpvbmVzIHdlcmUgdGhlIG1vc3Qgc2ltaWxhciBpbiBjb21wb3NpdGlvbiBhbmQgaGFkIHRoZSBncmVhdGVzdCBudW1iZXIgb2Ygc2hhcmVkIEJJTnMgYXQgNjU0IChmaWdzLiA1LDYpLCByZXByZXNlbnRpbmcgNzglIG9mIHRoZSBCSU5zIGZyb20gdGhlIGV4dHJlbWUgbGF0aXR1ZGUgY29tbXVuaXR5IGFuZCAyMiUgb2YgdGhlIHRlbXBlcmF0ZSBjb21tdW5pdHkuIFRoaXMgd2FzIGNvbnRyYXN0ZWQgYnkgdGhlIHJlbGF0aXZlbHkgZmV3IGJpbnMgc2hhcmVkIGJldHdlZW4gdGhlIHRyb3BpY2FsLCBzdWItdHJvcGljYWwsIGFuZCB0ZW1wZXJhdGUgem9uZXMuIEZyb20gb3JkaW5hdGlvbiwgd2Ugc2VlIHRoYXQgdGhlIGV4dHJlbWUgYW5kIHRlbXBlcmF0dXJlIGNvbW11bml0aWVzIGFyZSBtb3N0IHNpbWlsYXIgaW4gdGVybXMgb2YgY29tcG9zaXRpb24gd2hpbGUgdGhlIHN1Yi10cm9waWNhbCBhbmQgdHJvcGljYWwgem9uZXMgYXJlIGFzIGRpc3NpbWlsYXIgdG8gdGhlIHRlbXBlcmF0ZSBhbmQgZXh0cmVtZSB6b25lcyBhcyB0aGV5IGFyZSB0byBlYWNoIG90aGVyLgoKPCEtLSBUaGUgc2FtcGxpbmcgZWZmb3J0IGluIHNvbWUgY291bnRyaWVzIGlzIGVzcGVjaWFsbHkgc3VzcGVjdC4gIC0tPgoKVGhlIG1hcHBpbmcgb2Ygc3BlY2ltZW5zIGFuZCByYXJlZmFjdGlvbiBjdXJ2ZXMgcHJvZHVjZWQgZnJvbSBCSU4gYWJ1bmRhbmNlcyBieSBjb3VudHJ5IGFuZCBsYXRpdHVkZSB6b25lIChmaWcuIDIpIGJvdGggc2hvdyBhIHN0cm9uZyBnZW9ncmFwaGljIGJpYXMgaW4gdGhlIGRhdGFiYXNlIGFuZCBhbiB1bmRlci1wb3dlcmVkIHNhbXBsaW5nIG9mIG1hbnkgcmVnaW9ucywgcGFydGljdWxhcmx5IGF0IHRyb3BpY2FsIGxhdGl0dWRlcy4gRGVzcGl0ZSB0aGUgd2lkZSByYW5nZSBvZiBzb3VyY2UgY291bnRyaWVzLCBDYW5hZGlhbiBzcGVjaW1lbnMgYWNjb3VudCBmb3IgbmVhcmx5IGhhbGYgdGhlIGNvbGxlY3Rpb24gd2l0aCB0aGUgcmVtYWluaW5nIHJlY29yZHMgYmVpbmcgcHJlZG9taW5hbnRseSBmcm9tIHRoZSBVUyBhbmQgaGFuZGZ1bCBvZiBvdGhlciBjb3VudHJpZXMuIFRoaXMgJ0JvcmVhbCBiaWFzJyBpcyBhIHByZXZhbGVudCB0aGVtZSBpbiBlY29sb2d5IFtAUGxhdG5pY2sxOTkxXSBhbmQgdGhlIEJPTEQgZGF0YSByZWZsZWN0cyB0aGlzLiBBcyBzdWNoLCBzb21lIHJlc3VsdHMgb2YgdGhpcyBkaXZlcnNpdHkgYW5hbHlzaXMgYXJlIHBhcnRpY3VsYXJseSBzdXNwZWN0LiBCcmF6aWwsIGZvciBleGFtcGxlLCBhcHBlYXJzIHRvIGhhdmUgZXh0cmVtZWx5IGxvdyBzcGlkZXIgZGl2ZXJzaXR5IGJ1dCB0aGlzIGlzIGNvbnRyYXJ5IHRvIHdoYXQgaXMgZXhwZWN0ZWQgZnJvbSB0aGUgbGF0aXR1ZGUtZGl2ZXJzaXR5IHRyZW5kIGFuZCB0aGUgaGlnaGx5LXByb2R1Y3RpdmUgbGFuZHNjYXBlLgoKPCEtLSBjb25jbHVzaW9uIC0tPgpJbiBzdW1tYXJ5LCBCT0xEIGRhdGEgc2hvdyBkZWNyZWFzaW5nIHRyZW5kIGluIHNwaWRlciBiaW9kaXZlcnNpdHkgd2l0aCBkaXN0YW5jZSBmcm9tIHRoZSBlcXVhdG9yIGFzIGhhcyBiZWVuIHByZXZpb3VzbHkgZGVzY3JpYmVkIFtAUGllbDIwMTgsIEBQbGF0bmljazE5OTFdLiBUaGVyZSBpcyBncmVhdCB2YXJpYXRpb24gaW4gZGl2ZXJzaXR5IGJldHdlZW4gY291bnRyaWVzIGluIHRoZSBCT0xEIGRhdGEgYW5kIGEgbGltaXRlZCBudW1iZXIgb2YgdHJvcGljYWwgY291bnRyaWVzIHdpdGggYWRlcXVhdGUgc2FtcGxpbmcuIFRoaXMgbWFkZSBpdCBkaWZmaWN1bHQgZmluZCBzaWduaWZpY2FudCBjaGFuZ2VzIGluIHJpY2huZXNzIG9yIGRpdmVyc2l0eSBhY3Jvc3MgbGF0aXR1ZGVzLiBTYW1wbGluZyBiaWFzIGhhcyBhZmZlY3RlZCB0aGUgYW5hbHlzaXMgdG8gYW4gZXh0ZW50IGJ1dCB0aGlzIGlzIHNvbWV3aGF0IGNvbXBlbnNhdGVkIGZvciBieSB0aGUgbGFyZ2Ugdm9sdW1lIG9mIHNwZWNpbWVucyBjb2xsZWN0ZWQgYW5kIHRoZSB1c2Ugb2YgYnJvYWQgbGF0aXR1ZGUgem9uZXMuIFRoZSBCT0xEIGRhdGFiYXNlIGlzIGluZGVlZCBhIHZhbHVhYmxlIHJlc291cmNlIGZvciBldmFsdWF0aW5nIGdsb2JhbCBlY29sb2dpY2FsIHRyZW5kcy4gQk9MRCdzIHZhbHVlIHdpbGwgY29udGludWUgdG8gaW5jcmVhc2Ugd2l0aCB0aGUgYWRkaXRpb24gb2YgY29sbGVjdGlvbnMgZnJvbSB1bmRlci1yZXByZXNlbnRlZCBhcmVhcy4KCgojIENvZGUgYW5kIHN1cHBsZW1lbnRhbAoKUGxlYXNlIGZpbmQgdGhlIGNvZGUgdXNlZCB0byBjcmVhdGUgdGhpcyB3b3JrIGluIHRoZSBmaWxlIGBKTW9nZ19zcGlkZXJfZGl2ZXJzaXR5X25vdGVib29rLm5iLmh0bWxgIHdoZXJlIGl0IGlzIHByZXNlbnRlZCBpbiB0aGUgJ2xpdGVyYXRlIHByb2dyYW1taW5nJyBzdHlsZS4gVGhpcyBwZGYgZG9jdW1lbnQgYW5kIHRoZSBub3RlYm9vayB3ZXJlIHJlbmRlcmVkIGZyb20gUm1hcmtkb3duIGZpbGVzIGBKTW9nZ19zcGlkZXJfZGl2ZXJzaXR5X3BkZi5SbWRgIGFuZCBgSk1vZ2dfc3BpZGVyX2RpdmVyc2l0eV9ub3RlYm9vay5SbWRgLCByZXNwZWN0aXZlbHkuIEZpZ3VyZXMgaGF2ZSBiZWVuIGxhYmVsbGVkIGluIHRoZSBvcmRlciB0aGF0IHRoZXkgYXBwZWFyIGluIHRoZSBwZGYgZm9ybWF0LgoKLS0tLS0KCiMgQWNrbm93bGVkZ2VtZW50cwoKV2UgdHJ1bHkgc3RhbmQgb24gdGhlIHNob3VsZGVycyBvZiBnaWFudHMgYW5kIEkgZm91bmQgdGhlIGZvbGxvd2luZyB0dXRvcmlhbHMgdmVyeSBoZWxwZnVsIHdoaWxlIGNyZWF0aW5nIHRoaXMgd29yazoKCi0gVmVnYW4gVHV0b3JpYWwgYnkgUGV0ZXIgQ2xhcmsgaHR0cHM6Ly9wZWF0LWNsYXJrLmdpdGh1Yi5pby9CSU8zODEvdmVnYW5UdXRvcmlhbC5odG1sIAoKLSBNb3NxdWl0byBjb21tdW5pdHkgZGl2ZXJzaXR5IGFuYWx5c2lzIHdpdGggdmVnYW4gYnkgUmFuZGkgSCBHcmlmZmluIGh0dHA6Ly93d3cucmFuZGlncmlmZmluLmNvbS8yMDE3LzA1LzIzL21vc3F1aXRvLWNvbW11bml0eS1lY29sb2d5LWluLXZlZ2FuLmh0bWwKCi0gTmV0d29yayBBbmFseXNpcyBhbmQgVmlzdWFsaXphdGlvbiB3aXRoIFIgYW5kIGlncmFwaCBieQpLYXRoZXJpbmUgT2dueWFub3ZhIGh0dHBzOi8va2F0ZXRvLm5ldC9uZXRzY2l4MjAxNi5odG1sCgotLS0tLQoKIyBSZWZlcmVuY2VzCgo8IS0tIGJpYmxpb2dyYXBoeSBmcm9tIHJlZmVyZW5jZXMuYmliIGlzIGluc2VydGVkIGF0IGVuZCBvZiBwZGYgd2hlbiBrbml0dGluZyAtLT4KCgoKCjwhLS0gYGBge3J9IC0tPgo8IS0tIGF0dGFjaChhbHBoYS5kaXZlcnNpdHkuY291bnRyeSkgLS0+CjwhLS0gbW9kZWwxIDwtIGxtKFJhcmVmaWVkIH4gem9uZSkgLS0+CjwhLS0gc3VtbWFyeShtb2RlbDEpIC0tPgo8IS0tIGFub3ZhKG1vZGVsMSkgLS0+CjwhLS0gcGxvdChSYXJlZmllZH5ab25lKSAtLT4KCjwhLS0gbW9kZWwyIDwtIGxtKFNoYW5ub24gfiB6b25lKSAtLT4KPCEtLSBzdW1tYXJ5KG1vZGVsMikgLS0+CjwhLS0gYW5vdmEobW9kZWwyKSAtLT4KPCEtLSBwbG90KFNoYW5ub25+em9uZSkgLS0+CjwhLS0gYGBgIC0tPgo=